JDK针对Lock的主要实现是ReentrantLock,ReadWriteLock实现是ReentrantReadWriteLock。本文主要介绍ReentrantLock。ide
两把锁共享一个等待队列,两把锁的状态都由一个原子变量表示,特有的获取锁和释放锁逻辑。性能
注: 这里的响应中断意思是若被其余线程中断(调用interrupt方法)会抛出InterruptedException异常。this
AQS-AbstractQueuedSynchronizer(抽象队列同步器)。线程
ReadWriteLock在内部注入了AbstractQueuedSynchronizer,上锁和释放锁核心方法都在AQS类当中,AQS维护了两个核心变量,一个是state(当前可重入计数,初始值为0),一个是exclusiveOwnerThread(当前持有锁的线程Thread对象)。另外还维护了一个锁等待队列。code
ReentrantLock构造方法传入的boolean值ture为公平锁,false为不公平锁。以不公平锁为例先讲一下上锁和释放锁的原理:对象
就是将AQS内的state变量的值递减1,若是state值为0,则完全释放锁,会将“加锁线程”变量也设置为null,同时唤醒等待队列中的第一个线程。队列
为何说上面的是不公平锁,释放锁时不是唤醒队列中第一个线程吗?为何还会出现不公平的状况了,缘由在于若是恰好释放锁,此时有一个线程进来尝试获取锁,可能会存在插队的状况。同步
构造方法bollean传入true则表明的是公平锁,在获取锁方法中多了一个检查,意义是只有不存在其余等待时间更长的线程,它才会尝试获取锁。对比不公平锁,其总体性能比较低,低的缘由不是这个检查慢,而是会让活跃线程得不到锁,进入等待状态,引发上下文切换,下降了总体的效率,it
建议: synchronized之前的效率不如显式锁,但如今的版本二者效率上几乎没有区别,因此建议能用synchronized就用synchronized,须要实现synchronized办不到的需求如以上区别时,再考虑ReentrantLock。io
与wait和notify对应,用于线程协做,经过Lock的Condition newCondition()方法建立对应显示锁的显示条件;
主要方法是await()和signal(),await()对应于Object的wait(),signal()对应于notify,signalAll()对应于notifyAll()
public class WaitThread extends Thread { private volatile boolean fire = false; private Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); @Override public void run() { try { lock.lock(); try { while (!fire) { condition.await(); } } finally { lock.unlock(); } System.out.println("fired"); } catch (InterruptedException e) { Thread.interrupted(); } } public void fire() { lock.lock(); try { this.fire = true; condition.signal(); } finally { lock.unlock(); } } public static void main(String[] args) throws InterruptedException { WaitThread waitThread = new WaitThread(); waitThread.start(); Thread.sleep(1000); System.out.println("fire"); waitThread.fire(); } }
当主线程调用fire方法时,子线程才被唤醒继续执行。