想了解混合synced的新动态吗?本文将为您提供详细的信息,我们还将为您解答关于与ReentrantLock.lock的相关问题,此外,我们还将为您介绍关于15reentrantlock替代synch
想了解混合synced的新动态吗?本文将为您提供详细的信息,我们还将为您解答关于与ReentrantLock.lock的相关问题,此外,我们还将为您介绍关于15 reentrantlock替代synchronized、java synchronized ReentrantLock、java 篇之 Lock、ReentrantLock、synchronized、JAVA 重入锁 synchronized+ReentrantLock的新知识。
本文目录一览:- 混合synced()与ReentrantLock.lock()(混合模式详解)
- 15 reentrantlock替代synchronized
- java synchronized ReentrantLock
- java 篇之 Lock、ReentrantLock、synchronized
- JAVA 重入锁 synchronized+ReentrantLock
混合synced()与ReentrantLock.lock()(混合模式详解)
在Java中,这样做ReentrantLock.lock()
并ReetrantLock.unlock()
使用相同的锁定机制synchronized()
?
我的猜测是“不”,但我希望是错的。
例:
想象一下,线程1和线程2都可以访问:
ReentrantLock lock = new ReentrantLock();
线程1运行:
synchronized (lock) { // blah}
线程2运行:
lock.lock();try { // blah}finally { lock.unlock();}
假设线程1首先到达其部分,然后在线程1完成之前到达线程2:线程2将等待线程1离开该synchronized()
块,还是继续运行?
答案1
小编典典不,lock()
即使线程1synchronized
在同一线程上,线程2也可以lock
。这是文档必须说的:
请注意,Lock实例只是普通对象,它们本身可以用作同步语句中的目标。获取Lock实例的监视器锁与调用该实例的任何lock()方法没有指定的关系。建议避免混淆,除非在自己的实现中使用,否则不要以这种方式使用Lock实例。
15 reentrantlock替代synchronized
注意:reentrantlock必须要手动释放锁。
synchronized是手动上锁,自动释放。 reentrantlock是自动上锁,自动释放。
效果:执行完m1之后才能执行m2 代码:
/**
* reentrantlock用于替代synchronized
* 由于m1锁定this,只有m1执行完毕的时候,m2才能执行
* 这里是复习synchronized最原始的语义
*
* 使用reentrantlock可以完成同样的功能
* 需要注意的是,必须要必须要必须要手动释放锁(重要的事情说三遍)
* 使用syn锁定的话如果遇到异常,jvm会自动释放锁,但是lock必须手动释放锁,因此经常在finally中进行锁的释放
* @author mashibing
*/
package yxxy.c_020;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLock2 {
Lock lock = new ReentrantLock();
void m1() {
//写try...catch..finally或者try..finally
try {
lock.lock(); //synchronized(this)
for (int i = 0; i < 10; i++) {
TimeUnit.SECONDS.sleep(1);
System.out.println(i);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//释放锁
lock.unlock();
}
}
void m2() {
//锁定同一把锁,即可互斥
lock.lock();
System.out.println("m2 ...");
lock.unlock();
}
public static void main(String[] args) {
ReentrantLock2 rl = new ReentrantLock2();
new Thread(rl::m1).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(rl::m2).start();
}
}
java synchronized ReentrantLock
ReentrantLock重入锁简单理解就是对同一个线程而言,它可以重复的获取锁。例如这个线程可以连续获取两次锁,但是释放锁的次数也一定要是两次
Lock lock=new ReentrantLock(true);//公平锁
Lock lock=new ReentrantLock(false);//非公平锁
公平锁指的是线程获取锁的顺序是按照加锁顺序来的,而非公平锁指的是抢锁机制,先lock的线程不一定先获得锁。Java的synchronized关键字就是非公平锁
package com.example.web.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; @RestController public class ThreadController { //测试每次请求是否重新初始化 int single = 0; private ReentrantLock lock = new ReentrantLock(); private ReentrantReadWriteLock lockRW = new ReentrantReadWriteLock(); //设置程序进入等待状态 private Condition condition = lock.newCondition(); @RequestMapping("thread") public int test() { //练习锁机制,开启几个线程 for (int i = 0; i < 5; i++) { new Thread(() -> { try { lock.lock(); //此处测试线程等待和线程唤醒 System.out.println("线程进入等待状态"); condition.await(); thread(); } catch (Exception ex) { } finally { lock.unlock(); } }).start(); } single++; System.out.println(single); return single; } //写一个方法用来唤醒线程 @RequestMapping("/thread/signal") public void signal() { lock.lock(); condition.signal(); lock.unlock(); System.out.println("线程已被唤醒"); } //写一个方法用来多线程调用 public void thread() throws Exception { //写个循环用来多线程干扰 for (int i = 0; i < 5; i++) { System.out.println("线程" + i + ":" + Thread.currentThread().getName()); //得稍微耗时一下才行 Thread.sleep(50); } } }
private ReentrantReadWriteLock lockRW = new ReentrantReadWriteLock();//读写锁
Lock类有读锁和写锁,读读共享,写写互斥,读写互斥
参考链接:https://www.cnblogs.com/-new/p/7256297.html
java原子类使用的就是原子锁,核心方法就是compareAndSet,也就是常说的CAS,用来对比更新,写一段伪代码,current会和实际值对比,如果相同则更新成next值,否则继续循环。
public final int incrementAndGet() { for (; ; ) { //获取当前值 int current = get(); //设置期望值 int next = current + 1; //调用Native方法compareAndSet,执行CAS操作 if (compareAndSet(current, next)) //成功后才会返回期望值,否则无线循环 return next; } }
synchronized有lock的区别特点总结:
synchronized是在jvm层实现的锁机制,代码在执行异常时,会自动释放线程占用的锁,不会出现死锁。而Lock发生异常没有进行unLock进行释放很可能会产生死锁。
lock在等待锁时候,可以中断去执行其他代码,但是synchronized会一直等待,直到拿到锁为止。
lock可以知道是否拿到锁,synchronized无法判断是否拿到锁。
lock可以提高多线程读操作,因为读操作无需锁,
lock性能相对较高(看其他人说的),但是一定需要手工释放锁。
找到一篇讲的非常不错的博客必须安利下:
https://blog.csdn.net/javazejian/article/details/72828483
讲解自旋锁等相关知识:
https://blog.csdn.net/qq_34337272/article/details/81252853
https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484911&idx=1&sn=1d53616437f50b353e33edad6fda2e4f&source=41#wechat_redirect
各种锁介绍:https://www.cnblogs.com/lzh-blogs/p/7477157.html
java 篇之 Lock、ReentrantLock、synchronized

1、什么是锁
锁是 java 来保证线程安全的一种手段,当程序处于并发环境下运行的时候,共享数据没有及时刷新到主内存当中,造成其他线程读取到的是历史缓存数据,为了保证数据的正确性,java 提供了锁的机制来
2、synchronized 和 ReentrantLock
ReentrantLock 是 jdk 5 提供出来的一种高伸缩性的锁,synchronized 在 jdk 6 已经修改成和 ReentrantLock 一样的内部算法,所有在性能问题上 synchronized 已经和 ReentrantLock 接近,但是 ReentrantLock 提供了更多操作锁的方法
2.1 synchronized
一般我们使用 synchronized (obj) 方式来使用同步锁,记住,最好不要用 synchronized (this) 方式,这种方式存在一个问题,比如 A 先获取到锁,B 本来是 A 无关联的类,但是由于使用这种方式(锁住当前对象),B 必须等待 A 的锁先释放才可以获取到锁,性能低下
public class Test{
public void A(){
synchronized(this){
}
}
public void B(){
synchronized(this){
}
}
}
2.2 ReentrantLock
ReentrantLock 作为 jdk 5 出来的一种新的锁的方式完全可以替代 synchronized,ReentrantLock 有 3 中锁的方式,我们来一一对比下
package main.test.thead; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * Created by ping on 2017/8/20. */ public class LockTest { private static int count = 0; private static final CountDownLatch start = new CountDownLatch(1); private static final CountDownLatch end = new CountDownLatch(10); private static final Object obj = new Object(); private static final ReentrantLock lock = new ReentrantLock(); public static void main(String[] args) throws InterruptedException { for (int i =0 ;i < 100 ;i++){ Thread thread = new Thread(new Runnable() { @Override public void run() { try { start.await(); //task //这里可以是 lock.lock(),lock.lockInterruptibly() if(lock.tryLock(10L,TimeUnit.SECONDS)){ try { System.out.println(count++); }catch (Exception e){ e.printStackTrace(); } finally { lock.unlock(); } }else{ System.out.println("获取锁失败..."); } } catch (InterruptedException e) { e.printStackTrace(); }finally { end.countDown(); } } }); thread.start(); } start.countDown(); end.await(); } }
1、lock.lock () 方式,这种方式是阻塞的(没有获取到锁会一直等待,线程处于休眠状态),功能基本和 synchronized 一样
2、lock.tryLock () 方式,这种方式如果没有获取到锁,立即放回 false(不阻塞),执行接下来的业务逻辑,可以设置等待时间
上面两种方式都不会响应线程中断
3、lock.lockInterruptibly (), 这种方式也是阻塞的,但是如果当前线程中断,那么线程会从休眠中唤醒来响应线程中端
JAVA 重入锁 synchronized+ReentrantLock
1 重入锁:线程重复获得已经持有的锁,锁有一个"持有计数器"跟踪锁的嵌套
2 锁和条件的作用
锁:用来保护代码片段,任何时候同一个对象只能有一个线程执行被某一个锁保护的代码
锁:管理试图进入被保护代码片段的线程,同一对象的一个锁在同一时间只能被一个线程持有
锁:可以拥有多个不同的条件对象
条件对象:管理已经持有锁(已进入保护代码片段),但是不满足某个条件不能继续的线程,使其暂时放弃锁,并进入等待条件对象唤醒。
3 synchronized与ReentrantLock原理相同,synchronized是对象的内部锁并持有一个内部条件对象
4 建议共享对象的同一个成员变量的所有修改方法都要使用同一个锁。
ReentrantLock例
public class LockTest {
ReentrantLock lock1=new ReentrantLock();
ReentrantLock lock2=new ReentrantLock();
public void test1() throws InterruptedException {
lock1.lock();
System.out.println(Thread.currentThread().getName()+" get lock1 test1()");
test4();//尝试获得lock2锁
test2(); //尝试再次进入lock1锁
System.out.println(Thread.currentThread().getName()+" unlock lock1 test1()");
lock1.unlock();
}
public void test2() throws InterruptedException {
lock1.lock();
System.out.println(Thread.currentThread().getName()+" get lock1 test2()");
System.out.println(Thread.currentThread().getName()+" unlock lock1 test2()");
lock1.unlock();
}
public void test3() throws InterruptedException {
lock2.lock();
System.out.println(Thread.currentThread().getName()+" get lock2 test3()");
System.out.println(Thread.currentThread().getName()+" sleep in lock2");
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName()+" unlock lock2 test3()");
lock2.unlock();
}
public void test4() throws InterruptedException {
System.out.println(Thread.currentThread().getName()+" into test4() try get lock2");
lock2.lock();
System.out.println(Thread.currentThread().getName()+" get lock2 test4()");
System.out.println(Thread.currentThread().getName()+" unlock lock2 test4()");
lock2.unlock();
}
public static void main(String[] args) throws InterruptedException {
LockTest lTest=new LockTest();
FastWork fastWork=new FastWork(lTest);
Thread t1=new Thread(fastWork, "T1");
t1.start();
lTest.test1();
}
}
class FastWork implements Runnable{
LockTest lTest;
public FastWork(LockTest lTest) {
super();
this.lTest = lTest;
}
@Override
public void run() {
try {
lTest.test3(); //尝试获得lock2锁
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行结果
T1 get lock2 test3()
main get lock1 test1()
T1 sleep in lock2
main into test4() try get lock2
T1 unlock lock2 test3()
main get lock2 test4()
main unlock lock2 test4()
main get lock1 test2()
main unlock lock1 test2()
main unlock lock1 test1()
LockTest lTest时两个线程的共享对象,test1()+test2()被lock1保护,test3()+test4()被lock2保护。
1.当T1线程进入test3()获得lock2后,再T1释放lock2之前,main线程不能访问被lock2保护的所有代码片段。main线程进入test4()后,当到达lock2.lock()时阻塞了,直到T1线程放弃lock2,main线程才能继续执行test4()中被lock2保护代码片段。
2.main线程已经获得lock1,之后可以再进入其他任意lock1保护的代码片段,因为此时其他任意线程不能进入lock1保护的代码片段。重入锁的特点
3.可以看出lock1+lock2互不影响,所以建议共享对象的一个成员变量的所有修改方法都要使用同一个锁。否则两个修改方法用不同锁保护,则可能会有两个线程同时修改同一个成员变量。
synchronized客户端锁例
public class LockTest1 {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch=new CountDownLatch(1);
OneTest oneTest=new OneTest();
LockTestWork work=new LockTestWork(oneTest, countDownLatch);
Thread t1=new Thread(work);
t1.start();
Thread.sleep(1000);
synchronized (oneTest) {//客户端锁
System.out.println(Thread.currentThread().getName()+" sleep ");
countDownLatch.countDown(); //告诉t1 可以行动
Thread.sleep(5000);
}
}
}
class LockTestWork implements Runnable{
OneTest oneTest;
CountDownLatch countDownLatch;
public LockTestWork(OneTest oneTest, CountDownLatch countDownLatch) {
super();
this.oneTest = oneTest;
this.countDownLatch = countDownLatch;
}
public LockTestWork(OneTest oneTest) {
super();
this.oneTest = oneTest;
}
@Override
public void run() {
try {
countDownLatch.await();
oneTest.setName("123");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class OneTest{
private String name="";
public String getName() {
return name;
}
public synchronized void setName(String name) {
System.out.println(Thread.currentThread().getName()+" get synchronized 锁 ");
this.name = name;
}
}
运行结果:
main sleep
Thread-0 get synchronized 锁 //5秒之后
上面例子说明:
synchronized (oneTest) {} 锁的代码段,这段代码获得是oneTest对象的synchronized锁,主线程获得所以后睡眠5秒,这5秒Thread-0不能执行setName()。因为他不能获得oneTest对象的synchronized锁,所以阻塞。
关于混合synced和与ReentrantLock.lock的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于15 reentrantlock替代synchronized、java synchronized ReentrantLock、java 篇之 Lock、ReentrantLock、synchronized、JAVA 重入锁 synchronized+ReentrantLock等相关知识的信息别忘了在本站进行查找喔。
本文标签: