开发者

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

目录
  • 一、synchronized 有不足
  • 二、改进意见
  • 三、可抢占的方法论
    • 3.1 能够响应中断
    • 3.2 支持超时
    • 3.3 非阻塞地获取锁
  • 四、可抢占的实现 - JUC 的 locks
    • 五、多个 Condition(条件变量或条件等待队列)
      • 六、JUC中locks的使用规范
        • 6.1 保证锁的释放
        • 6.2 循环体中使用 await()
        • 6.3 同步代码块中使用 await()

      一、synchronized 有不足

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

      JUC 的 locks 就是对 synchronized 的补充

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

      二、改进意见

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

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

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

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

      三、可抢占的方法论

      3.1 能够响应中断

      synchronized 的问题是:持有锁 A 后,如果尝试获取锁 B 失败,那么线程就进入阻塞状态,一旦发生死锁,就没有任何机会来唤醒阻塞的线程。但如果开发者_Go开发阻塞状态的线程能够响应中断信号,也就是说当我们给阻塞的线程发送中断信号的时候,能够唤醒它,那它就有机会释放曾经持有的锁 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(条件变量或条件等待队列)

      等效于管程中的条件变量,条件变量用于线程间的同步。通过javhttp://www.devze.coma.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 示例:一个有界缓冲,两个条件等待队列,分别被生产者线程和消费者线程来使用。

      • mHEMda产者线程在 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.simHEMdagnal();
           return x;
         } finally {
           lock.unlock();
         }
       }
      }
      

      六、JUC中locks的使用规范

      6.1 保证锁的释放

       Lock l = ...;
       l.lock();
       try {
         // Access the resource protected by this lock
       } f编程客栈inally {
         l.unlock();
       }
      
       Lock lock = ...;
       if (lock.tryLock()) {
         try {
           // manipulate protected sthttp://www.devze.comate
         } 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 的资料请关注我们其它相关文章!

      0

      上一篇:

      下一篇:

      精彩评论

      暂无评论...
      验证码 换一张
      取 消

      最新开发

      开发排行榜