ReentrantLock能够实现很多synchronized无法做到的细节控制,比如公平性fairness,或者利用定义条件等。
知识点扩展:
保证多线程环境下 共享的、可修改的 状态的正确性。
进而推导出保证线程安全的两个方法:
synchronized如果用来修饰静态方法,相当于 synchronized (ClassName.class) {}
ReentrantLock如果当一个线程试图获取一个它已经获取的锁时,会自动成功。
ReentrantLock可以指定公平性 ReentrantLock fairLock = new ReentrantLock(true);
,为真时,会倾向于将锁赋予等待时间最久的线程。
ReentrantLock相比synchronized,因为可以像普通对象一样使用,所以可以利用其提供的各种便利方法,进行精细的同步操作:
如果说 ReentrantLock 是 synchronized的替代,则Condition则是将wait、notify、notifyAll转化为相应的对象,将复杂而晦涩的同步操作转变为直观可控的对象行为。
ArrayBlockingQueue
两个条件变量从 同一个再入锁 创建出来。
/** Condition for waiting takes */
private final Condition notEmpty;
/** Condition for waiting puts */
private final Condition notFull;
public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
this.items = new Object[capacity];
lock = new ReentrantLock(fair);
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
notEmpty.await();
return dequeue();
} finally {
lock.unlock();
}
}
private void enqueue(E e) {
// assert lock.isHeldByCurrentThread();
// assert lock.getHoldCount() == 1;
// assert items[putIndex] == null;
final Object[] items = this.items;
items[putIndex] = e;
if (++putIndex == items.length) putIndex = 0;
count++;
notEmpty.signal(); // 通知等待的线程,非空条件已经满足
}