1. 介绍
- 在Lock接口出现之前,Java程序是靠synchronized关键字实现锁功能的,而Java SE 5之后,并发包中新增了Lock接口(以及相关实现类)用来实现锁功能,它提供了与synchronized关键字类似的同步功能,只是在使用时需要显式地获取和释放锁。虽然它缺少了(通过synchronized块或者方法所提供的)隐式获取释放锁的便捷性,但是却拥有了锁获取与释放的可操作性、可中断的获取锁以及超时获取锁等多种synchronized关键字所不具备的同步特性。
- 使用synchronized关键字将会隐式地获取锁,但是它将锁的获取和释放固化了,也就是先获取再释放。当然,这种方式简化了同步的管理,可是扩展性没有显示的锁获取和释放来的好。例如,针对一个场景,手把手进行锁获取和释放,先获得锁A,然后再获取锁B,当锁B获得后,释放锁A同时获取锁C,当锁C获得后,再释放B同时获取锁D,以此类推。这种场景下,synchronized关键字就不那么容易实现了,而使用Lock却容易许多。
2. 使用方式
Lock lock = new ReentrantLock();
lock.lock();
try {
。。。
} finally {
lock.unlock();
}
- 在finally块中释放锁,目的是保证在获取到锁之后,最终能够被释放。
- 不要将获取锁的过程写在try块中,因为如果在获取锁(自定义锁的实现)时发生了异常,异常抛出的同时,也会导致锁无故释放。
3. Lock新特性
特性 |
描述 |
尝试非阻塞地获取锁 |
当前线程尝试获取锁,如果这一时刻锁没有被其他线程获取到,则成功获取并持有锁 |
能被中断的获取锁 |
与synchronized不同,获取到锁的线程能响应中断,当获取到锁的线程被中断时,中断异常将会抛出,且锁会被释放。 |
超时获取锁 |
在指定的截止时间之前获取锁,如果截止时间到了仍旧无法获取锁,则返回。 |
4. Lock API
public interface Lock {
//获取锁,调用该方法将会获取锁,当锁获取后,从该方法返回
void lock();
//可中断地获取锁,和lock()方法的不同之处在于该方法会响应中断,即在锁的获取过程中可以中断当前线程
void lockInterruptibly() throws InterruptedException;
//尝试非阻塞的获取锁,调用该方法后会立刻返回,如果能够获取则返回true,否则返回false
boolean tryLock();
//超时地获取锁 1、当前线程在超时时间内成功获取锁。2、当前线程在超时时间内被中断。3、超时时间结束返回false。
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
//释放锁
void unlock();
//获取等待通知组件
Condition newCondition();
}