锁是用来控制多个线程访问共享资源的方式,一般来说,一个锁能够防止多个线程同时访问共享资源(但是有些锁可以允许多个线程并发的访问共享资源,比如读写锁)。

Lock 的使用方式

  1. Lock lock = new ReentrantLock();
  2. lock.lock();
  3. try {
  4. } finally {
  5. lock.unlock();
  6. }

finally 块中释放锁,目的是保证在获取锁之后,最终能够被释放。
不要将获取锁的过程写在 try 块中,因为如果在获取锁(自定义锁的实现)时发生了异常,异常抛出的同时,也会导致锁无故释放。

Lock 接口和 synchronized 关键字 比较

Lock 接口提供了与 synchronized 关键字类似的同步功能,只是在使用时需要显示地获取和释放锁。虽然它缺少了(通过 synchronized 块或者方法所提供的)隐式获取释放锁的便捷性,但是却拥有了锁获取与释放的可操作性、可中断的获取锁以及超时获取锁等多种 synchronized 关键字所不具备的同步特性。

使用 synchronized 关键字将会隐式地获取锁,但是它将锁的获取和释放固化了,也就是先获取再释放。当然,这种方式简化了同步的管理,可是扩展性没有显示的锁获取和释放来的好。

Lock 接口提供的 synchronized 关键字不具备的主要特性

特 性 描 述
尝试非阻塞地获取锁 当前线程尝试获取锁,如果这一时刻锁没有被其他线程获取到,则成功获取并持有锁
能被中断地获取锁 与 synchronized 不同,获取到锁的线程能够响应中断, 当获取到锁的线程被中断时,中断异常将会被抛出,同时锁会被释放
超时获取锁 在指定的截止时间之前获取锁,如果截止时间到了仍旧无法获取锁,则返回