synchronized及JUC显式locks 使用原理解析

 更新时间:2022年12月26日 08:53:30   作者:Applehope  
这篇文章主要为大家介绍了synchronized及JUC显式locks 使用原理解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

一、synchronized 有不足

新事物的出现要不是替代老事物,要么就是对老事物的补充

JUC 的 locks 就是对 synchronized 的补充

  • 从开始竞争锁 到拿到锁这段时间,调用线程一直是阻塞状态,啥都干不了
  • 已经占有的资源也释放不了,别的线程也无法获得;这种不可抢占的情况,更容易带来死锁(死锁产生的原理就是:我占着你要用的资源不给你,你却不能抢)
  • 只有一个条件变量(条件等待队列),用于线程间的协调、通信

二、改进意见

采用更多的措施以避免死锁 :

不能抢占 变为 可抢占,占用部分资源的线程进一步申请其他资源时

  • 如果能快速申请到,就申请
  • 如果不能快速申请到,可以主动释放它占有的资源

使用者自己可创建多个条件变量,用于线程间的协调、通信。

三、可抢占的方法论

3.1 能够响应中断

synchronized 的问题是:持有锁 A 后,如果尝试获取锁 B 失败,那么线程就进入阻塞状态,一旦发生死锁,就没有任何机会来唤醒阻塞的线程。但如果阻塞状态的线程能够响应中断信号,也就是说当我们给阻塞的线程发送中断信号的时候,能够唤醒它,那它就有机会释放曾经持有的锁 A。这样就破坏了不可抢占条件了。

3.2 支持超时

如果线程在一段时间之内没有获取到锁,不是进入阻塞状态,而是返回一个错误,那这个线程也有机会释放曾经持有的锁。这样也能破坏不可抢占条件。

3.3 非阻塞地获取锁

如果尝试获取锁失败,并不进入阻塞状态,而是直接返回,那这个线程也有机会释放曾经持有的锁。这样也能破坏不可抢占条件。

四、可抢占的实现 - JUC 的 locks

// 支持中断的API
void lockInterruptibly() throws InterruptedException;
// 支持超时的API
boolean tryLock(long time, TimeUnit unit)  throws InterruptedException;
// 支持非阻塞获取锁的API
boolean tryLock();

五、多个 Condition(条件变量或条件等待队列)

等效于管程中的条件变量,条件变量用于线程间的同步。通过java.util.concurrent.locks.Lock#newCondition()来创建,每个 Condition 都具有一个 waitSet;这样锁对象就具备了多个waitSet; Condition 提供了以下方法:用于线程的协作(线程等待/激活)。

//线程加入此条件变量的等待队列;类似Object.wait();使用时也要放到while循环体内。
java.util.concurrent.locks.Condition#await()
java.util.concurrent.locks.Condition#awaitUninterruptibly()
java.util.concurrent.locks.Condition#awaitNanos()
java.util.concurrent.locks.Condition#await(long, java.util.concurrent.TimeUnit)
java.util.concurrent.locks.Condition#awaitUntil()
//激活此条件变量中的一个线程;类似Object.notify()
java.util.concurrent.locks.Condition#signal()
//激活此条件变量中的所有线程;类似Object.notifyAll()
java.util.concurrent.locks.Condition#signalAll()

java doc 示例:一个有界缓冲,两个条件等待队列,分别被生产者线程和消费者线程来使用。

  • 生产者线程在 notFull 条件队列中等待;意思为生产者线程要阻塞等待,直到 有界缓冲不是满的,才能 put
  • 消费者线程在 notEmpty 条件队列中等待;意思为消费者线程要阻塞等待,直到有界缓冲不是空的,才能 take
class BoundedBuffer {
 final Lock lock = new ReentrantLock();
 final Condition notFull  = lock.newCondition();
 final Condition notEmpty = lock.newCondition();
 final Object[] items = new Object[100];
 int putptr, takeptr, count;
 public void put(Object x) throws InterruptedException {
   lock.lock();
   try {
     while (count == items.length)
       notFull.await();
     items[putptr] = x;
     if (++putptr == items.length) putptr = 0;
     ++count;
     notEmpty.signal();
   } finally {
     lock.unlock();
   }
 }
 public Object take() throws InterruptedException {
   lock.lock();
   try {
     while (count == 0)
       notEmpty.await();
     Object x = items[takeptr];
     if (++takeptr == items.length) takeptr = 0;
     --count;
     notFull.signal();
     return x;
   } finally {
     lock.unlock();
   }
 }
}

六、JUC中locks的使用规范

6.1 保证锁的释放

 Lock l = ...;
 l.lock();
 try {
   // access the resource protected by this lock
 } finally {
   l.unlock();
 }
 Lock lock = ...;
 if (lock.tryLock()) {
   try {
     // manipulate protected state
   } finally {
     lock.unlock();
   }
 } else {
   // perform alternative actions
 }

6.2 循环体中使用 await()

while (XXX)
    condition.await();

6.3 同步代码块中使用 await()

必须先持有锁

 l.lock();
 try {
    ...
    while (XXX)
      condition.await();
    ...
 } finally {
   l.unlock();
 }

以上就是synchronized及JUC显式locks 使用原理解析的详细内容,更多关于synchronized JUC显式locks 的资料请关注脚本之家其它相关文章!

相关文章

  • Java中设置JAVA_HOME无效的解决方法

    Java中设置JAVA_HOME无效的解决方法

    最近遇到一个问题,就是配置JAVA_HOME无效,不管怎么改,运行Java -version始终是最初的那个java版本,所以这篇文章主要给大家介绍了关于Java中设置JAVA_HOME无效的解决方法,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-09-09
  • 解析Spring中面向切面编程

    解析Spring中面向切面编程

    如果说 IoC 是 Spring 的核心,那么面向切面编程就是 Spring 最为重要的功能之一了,在数据库事务中切面编程被广泛使用
    2021-06-06
  • java实战案例之用户注册并发送邮件激活/发送邮件验证码

    java实战案例之用户注册并发送邮件激活/发送邮件验证码

    现在很多的网站都提供有用户注册功能,当我们注册成功之后就会收到封注册网站的邮件,邮件里包含了我们的注册的用户名和密码及激活账户的超链接等信息,这篇文章主要给大家介绍了关于java实战案例之用户注册并发送邮件激活/发送邮件验证码的相关资料,需要的朋友可以参考下
    2021-09-09
  • Spring MVC请求转发与请求重定向的示例详解

    Spring MVC请求转发与请求重定向的示例详解

    转发指服务器接收请求后,从一个资源跳转到另一个资源中,请求转发是一次请求,不会改变浏览器的请求地址,这篇文章主要介绍了Spring MVC请求转发与请求重定向的相关知识,需要的朋友可以参考下
    2023-09-09
  • java中的静态代码块、构造代码块、构造方法详解

    java中的静态代码块、构造代码块、构造方法详解

    下面小编就为大家带来一篇java中的静态代码块、构造代码块、构造方法详解。小编觉得挺好的,现在分享给大家。给大家一个参考。一起跟随小编过来看看吧
    2016-03-03
  • Java模拟计算机的整数乘积计算功能示例

    Java模拟计算机的整数乘积计算功能示例

    这篇文章主要介绍了Java模拟计算机的整数乘积计算功能,简单分析了计算机数值进制转换与通过位移进行乘积计算的原理,并结合具体实例给出了java模拟计算机成绩运算的相关操作技巧,需要的朋友可以参考下
    2017-09-09
  • Java的并发编程之CyclicBarrier解析

    Java的并发编程之CyclicBarrier解析

    这篇文章主要介绍了Java的并发编程之CyclicBarrier解析,CyclicBarrier支持一个可选的Runnable命令,在一组线程中的最后一个线程到达之后(但在释放所有线程之前),该命令只在每个屏障点运行一次,需要的朋友可以参考下
    2023-11-11
  • Java读取网络文件的实例代码

    Java读取网络文件的实例代码

    这篇文章主要介绍了Java读取网络文件的实例代码,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-07-07
  • IDEA插件之快速删除Java代码中的注释

    IDEA插件之快速删除Java代码中的注释

    这篇文章主要介绍了IDEA插件之快速删除Java代码中的注释,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-02-02
  • 如何使用IDEA的groovy脚本文件生成带JPA注解的实体类(图文详解)

    如何使用IDEA的groovy脚本文件生成带JPA注解的实体类(图文详解)

    这篇文章主要介绍了如何使用IDEA的groovy脚本文件生成带JPA注解的实体类,本文通过图文并茂实例相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-07-07

最新评论