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(); // 通知等待的线程,非空条件已经满足 }