新事物的出现要不是替代老事物,要么就是对老事物的补充
JUC 的 locks 就是对 synchronized 的补充
采用更多的措施以避免死锁 :
让不能抢占 变为 可抢占,占用部分资源的线程进一步申请其他资源时
使用者自己可创建多个条件变量,用于线程间的协调、通信。
synchronized
的问题是:持有锁 A 后,如果尝试获取锁 B 失败,那么线程就进入阻塞状态,一旦发生死锁,就没有任何机会来唤醒阻塞的线程。但如果阻塞状态的线程能够响应中断信号,也就是说当我们给阻塞的线程发送中断信号的时候,能够唤醒它,那它就有机会释放曾经持有的锁 A。这样就破坏了不可抢占条件了。
如果线程在一段时间之内没有获取到锁,不是进入阻塞状态,而是返回一个错误,那这个线程也有机会释放曾经持有的锁。这样也能破坏不可抢占条件。
如果尝试获取锁失败,并不进入阻塞状态,而是直接返回,那这个线程也有机会释放曾经持有的锁。这样也能破坏不可抢占条件。
// 支持中断的API void lockInterruptibly() throws InterruptedException; // 支持超时的API boolean tryLock(long time, TimeUnit unit) throws InterruptedException; // 支持非阻塞获取锁的API boolean tryLock();
等效于管程中的条件变量,条件变量用于线程间的同步。通过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 示例:一个有界缓冲,两个条件等待队列,分别被生产者线程和消费者线程来使用。
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(); } } }
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 }
while (XXX) condition.await();
必须先持有锁
l.lock(); try { ... while (XXX) condition.await(); ... } finally { l.unlock(); }