Lock接口在出现以前,Java使用synchronized关键字实现锁的功能。而在Java 1.5之后,Java新增了Lock接口及其实现类来实现类似synchronized关键字的功能。与synchronized隐式获取/释放锁不同的是,Lock接口获取/释放锁是显式的(需要调用Lock.lock()、Lock.unlock()方法)。此外Lock接口还拥有中断获取锁的线程、超时获取锁、尝试非阻塞获取锁等多种synchronized关键字所不具备的功能。
Lock lock = new ReentrantLock(); lock.lock(); try { ... } finally { lock.unlock(); } 复制代码
●不要将锁的获取放在try块中,因为若在锁的获取过程中(此时还未真正获取到锁)发生了异常,则在finally块中锁将会被无故释放(释放未获取到的锁也会发生异常)。
●要在finally块中释放锁,保证在获取到锁后,锁能被释放。
方法名称 | 描述 |
---|---|
void lock() | 当前线程尝试获取锁 |
void lockInterruptibly() throws InterruptedException | 可中断地获取锁,即在锁的获取中可以中断当前线程 |
boolean tryLock() | 尝试非阻塞地获取锁,调用该方法后立即返回,获取锁成功返回true,否则返回false |
boolean tryLock(long time,TimeUnit unit) throws InterruptedException | 超时获取锁 |
void unlock() | 释放锁 |
Condition newCondition() | 获取等待/通知组件,该组件和当前的锁绑定,当前线程只有获得了锁才能调用该组件的await()方法,调用await()方法后当前线程也将释放锁 |
AQS是构建锁或其他同步组件的基础框架,它使用了一个int成员变量来表示同步状态,通过内置的FIFO队列来完成资源获取线程(通常为获取锁的线程)的排队工作。
简单来说,AQS的主要使用方法是被子类继承,并且子类被推荐定义为同步组件的静态内部类。同步组件中聚合了AQS,利用AQS实现同步语义。(上述同步组件可以简单理解为自定义的锁)
锁是面向使用者的,锁定义了可供使用者调用的接口,屏蔽了锁的实现细节。AQS是面向锁的实现者的,它帮助简化了锁的实现,屏蔽了同步状态的管理、线程的排队、等待和唤醒等底层操作。锁和AQS很好地隔离了使用者和实现者所需关注的领域。
方法名称 | 描述 |
---|---|
protected boolean tryAcquire(int arg) | 独占式获取同步状态,实现该方法需要查询同步状态并判断其是否符合预期,若符合则用CAS设置成新的状态。 |
protected tryRelease(int arg) | 独占式释放同步状态。 |
protected int tryAcquireShared(int arg) | 共享式获取同步状态,若符合值大于等于0,表示获取同步状态成功,反之失败。 |
protected boolean tryReleaseShared(int arg) | 共享式释放同步状态。 |
protected boolean isHeldExclusively() | 当前同步状态是否在独占模式下已被获取。 |
方法名称 | 描述 |
---|---|
void acquire(int arg) | 独占式获取同步状态。若获取成功将从该方法返回,若获取失败线程将进入同步队列等待。此外该方法调用了重写的tryAcquire(int arg)方法。 |
void acquireInterruptibly(int arg) | 该方法是void acquire(int arg)方法的中断响应版本。进入同步队列的线程可被中断并抛出InterruptedException异常。 |
boolean tryAcquireNanos(int arg,long nanos) | 该方法是void acquireInterruptibly(int arg)方法的超时等待版本。 |
void acquireShared(int arg) | 共享式获取同步状态,和独占式获取的主要区别是同一时刻可以后多个线程获得同步状态。 |
void acquireSharedInterruptibly(int arg) | 该方法是void acquireShared(int arg)方法的中断响应版本。 |
boolean tryAcquireSharedNanos(int arg,long nanos) | 该方法是void acquireSharedInterruptibly(int arg)方法的超时等待版本。 |
boolean release(int arg) | 独占式释放同步状态。该方法将会调用重写的tryRelease(int arg)方法。 |
boolean releaseShared(int arg) | 共享式释放同步状态。 |
Collection< Thread >getQueueThreads() | 获取等待在同步队列上的线程集合。 |
同步器的设计是基于模板设计模式的,即自定义同步组件里的静态内部类继承了AQS后,重写了指定的方法。而同步器里的模板方法将被自定义同步组件调用,模板方法里则调用了重写的方法。
class Mutex implements Lock{ //静态内部类,自定义同步器 private static class Sync extends AbstractQueueSynchronizer{ //是否处于占用状态 protected boolean isHeldExclusively(){ return getState() == 1; } //当状态为0的时候获取锁 public boolean tryAcquire(int acquires){ if(compareAndSetState(0,1)){ setExclusiveOwnerThread(Thread.currentThread()); return true; } return false; } //释放锁,将状态设置为0 protected boolean tryRelease(int release){ if(getState() == 0)throw new IllegalMonitorStateException(); setExclusiveOwnerThread(null); setState(0); return true; } //返回一个Condition,每个condition都包含了一个condition队列 Condition newCondition(){ return new Condition(); } } //仅需要将操作代理到Sync上即可 private final Sync sync = new Sync(); public void lock(){sync.acquire(1)}; public boolean tryLock(){ return sync.tryAcquire(1); } public void unlock(){ sync.release(1); } public Condition newCondition(){ return sync.newCondition(); } public boolean isLocked(){ return sync.isHeldExclusively(); } public boolean hasQueuedTreads(){ return sync.hasQueuedTreads(); } public void lockInterruptibly() throws InterruptedException{ sync.acquireInterruptibly(1); } public boolean tryLock(long timeout,TimeUnit unit) throws InterruptedException{ return sync.tryAcquireNanos(1,unit.toNanos(timeout)); } } 复制代码