1 Lock接口
Java SE 5之后,并发包中新增了Lock接口(以及相关实现类)用来实现锁功能,它提供了与synchronized关键字类似的同步功能,只是在使用时 需要显式地获取和释放锁 。虽然缺少了(通过synchronized块或者方法所提供的)隐式获取释放锁的便捷性,但是却拥有了锁获取与释放的可操作性、可中断的获取锁以及超时获取锁等多种synchronized关键字所不具备的同步特性。
Lock接口的实现类:
- ReentrantLock
- ReentrantReadWriteLock.ReadLock
- ReentrantReadWriteLock.WriteLock
Lock lock = new ReentrantLock();
lock.lock();
try{
}finally{
lock.unlock()
}
synchronized锁和Lock锁的区别:
Lock接口的常用方法:
lock()
:获得锁unlock()
:释放锁。lockInterruptibly()
:可中断的获取锁,即在锁的获取中可以中断当前线程。tryLock()
:尝试非阻塞的获取锁,如果能够获取则立马返回true,否则直接返回false。tryLock(long time, TimeUnit unit)
:超时的获取锁,返回分三种情况
①当前线程在超时时间内获得了锁。
②当前线程在超时时间内被中断。
③超时,返回false。newCondition()
:获取等待通知组件,该组件和当前的锁绑定,当前线程只有获得了锁,才能调用组件的wait()方法,而调用后,当前线程将释放锁。
2 队列同步器(AQS)
Lock接口的实现基本都是通过聚合了一个同步器的子类来完成线程访问控制的。
队列同步器(AbstractQueuedSynchronizer,AQS),是用来构建锁或者其他同步组件的基础框架, 它使用了一个int成员变量表示同步状态,通过内置的FIFO队列来完成资源获取线程的排队工作 。
同步器的主要使用方式是继承,子类通过继承同步器并实现它的抽象方法来管理同步状态 ,同步器提供了三个方法对同步状态进行操作:
- getState():获取当前同步状态。
- setState(int newState):设置当前同步状态。
- compareAndSetState(int expect, int update):使用CAS设置当前状态,该方法能够保证状态设置的原子性。
子类推荐被定义为自定义同步组件的静态内部类 ,同步器自身没有实现任何同步接口,它仅仅是定义了若干同步状态获取和释放的方法来供自定义同步组件使用,同步器既可以支持独占式地获取同步状态,也可以支持共享式地获取同步状态,这样就可以方便实现不同类型的同步组件(ReentrantLock、ReentrantReadWriteLock和CountDownLatch等)。
同步器是实现锁的关键,在锁的实现中聚合同步器,利用同步器实现了锁的语义。同步器面向的是锁的实现者,它简化了锁的实现方式, 屏蔽了同步状态管理、线程的排队、等待与唤醒等底层操作 。锁和同步器很好地隔离了使用者和实现者所需关注的领域。
同步器中提供了大量的方法,使用者需要继承同步器并重写指定的方法。随后将同步器组合在自定义同步组件的实现中, 并调用同步器提供的模板方法,而这些模板方法将会调用使用者重写的方法。
同步器提供的模板方法基本上分为3类:
- 独占式获取与释放同步状态
- 共享式获取与释放同步状态
- 查询同步队列中的等待线程情况
自定义同步组件将使用同步器提供的模板方法来实现自己的同步语义。