在前文中,我们已经提到过java中一个重要的同步关键字synchronized。今天我们来介绍另一个重要的锁机制:ReentrantLock。
ReentrantLock提供了synchronized关键字一致的语义功能。但是提供了更丰富的使用场景。
- | ReentrantLock | synchronized |
---|---|---|
使用方式 | 需要显式的调用lock() 和unlock()
|
jvm保证锁的自动释放 |
等待 | 可中断,可设置超时 | 不支持 |
公平性 | 提供了公平锁/非公平锁 | 非公平锁 |
阻塞 |
tryLock() 实现非阻塞获取锁 |
只有阻塞 |
使用
ReentrantLock需要手动的释放锁,否则会导致其他线程永远无法获取到锁,因此总是记得用try{}finally{}
释放锁。
public void m() {
lock.lock(); // block until condition holds
try {
// ... method body
} finally {
lock.unlock()
}
}
ReentrantLock同时提供了Condition
条件变量,获取的方式是ReentrantLock.newCondition()
。
每一个条件变量有自己单独的等待队列,在调用Condition的await()
和signal()
方法时,必须先获取ReentrantLock的锁。
如果说ReentrantLock是用来代替synchronized,那Condition则是用来代替Object的wait(),notify()的,使用方式如下:
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();
}
}
}
结构
ReentrantLock只是简单的实现了Lock
接口和Serializable
接口。
从实现上来看,ReentrantLock更像是一个装饰器,其核心功能主要依赖内部的 Sync sync
变量,其中Sync的实现包括公平锁FairSync
和非公平锁NonFairSync
。Sync的实现里有一个重要的概念叫AQS(AbstractQueuedSynchronizer)
,我们将在下一片文章里单独讲解。
网友评论