Lock接口源代码分析


package java.util.concurrent.locks;
/**
 * 与使用{@code synchronized}方法和语句相比,{@code Lock}实现提供了更广泛的锁操作。
 * 它们允许更灵活的结构,可能具有完全不同的属性,并且可能支持多个关联的{@link Condition}对象。
 *
 * 

锁是一个控制多个线程访问共享资源的工具。通常,锁提供对共享资源的独占访问: * 每次只有一个线程可以获得锁,而对共享资源的所有访问都要求首先获得锁。 * 但是,有些锁可能允许并发访问共享资源,比如{@link ReadWriteLock}的读锁。 * *

{@code synchronized}方法或语句的使用提供与每个对象关联的隐式监控锁,但促使所有锁 * 获取和释放发生在块结构方式:在获得多个锁时,它们必须以相反的顺序被释放,而且所有的锁 * 都必须在相同的词法作用域获取。 * *

虽然{@code synchronized}方法和语句的作用域机制使用监控锁编程变得容易得多,并且有助于 * 避免许多涉及锁的常见编程错误,但是在某些情况下,您需要以更灵活的方式使用锁。例如,一 * 些遍历并发访问的数据结构的算法需要使用“hand-over-hand”;或者“链锁”:你获得节点A的锁, * 然后是节点B,然后释放A并获得C,然后释放B并获得D,以此类推。{@code Lock}接口的实现允许在 * 不同的范围内获取和释放一个锁,并允许以任何顺序获取和释放多个锁,从而支持使用这些技术。 * *

这种灵活性的增加带来了额外的处理。块结构锁的缺失消除了使用{@code synchronized} * 方法和语句时的锁自动释放。在大多数情况下,应该使用以下习语: * *

     Lock l = ...;
 *     l.lock();
 *     try {
 *         // 使用该锁访问受保护的资源
 *     } finally {
 *         l.unlock();
 *     }
 * 
* * 当锁定和解锁发生在不同的范围时,必须注意确保锁被持有时执行的所有代码都受到 * try-finally或try-catch的保护,以确保锁在必要时被释放。 * *

{@code Lock}实现提供超过{@code synchronized}同步方法和语句的使用方法, * 通过提供一个非阻塞的尝试获得一个锁({@link #tryLock()}),尝试获得锁可以被中 * 断({@link #lockInterruptibly},企图获得锁也可以设置超时({@link #tryLock(long, TimeUnit)})。 * *

{@code Lock}类还可以提供与隐式监控锁截然不同的行为和语义,例如保证顺序、不可重入使用或死锁检测。 * 如果实现提供了这种特殊的语义,那么实现必须记录这些语义。 * *

注意,{@code Lock}实例只是普通对象,它们本身可以用作{@code synchronized}语句中的目标。获取 * {@code lock}实例的监控锁与请求该实例的任何{@link #lock}方法没有指定的关系。为了避免混淆,建议 * 您永远不要以这种方式使用{@code Lock}实例,除非在它们自己的实现中使用。 * *

除非特别指出,为任何参数传递一个{@code null}值都会导致抛出一个{@link NullPointerException}。 * *

内存同步

* *

所有{@code Lock}实现必须强制执行内置监控锁提供的相同内存同步语义,如Java™语言规范的 * 第17.4章节描述的: *

    *
  • 一个成功的{@code lock}操作与一个成功的 lock 动作具有相同的内存同步效果。 *
  • 一个成功的{@code unlock}操作与成功的 unlock 操作具有相同的内存同步效果。 *
* *

不成功的锁定和解锁操作以及可重入锁定/解锁操作不需要任何内存同步效果。 * *

实现考虑

* *

三种形式的锁获取(可中断、不可中断和定时)在性能特征、顺序保证或其他实现质量方面可能有所不同。 * 此外,在给定的{@code lock}类中可能无法中断正在进行的获取锁。因此,实现不需要为所有三种形式的 * 锁获取定义完全相同的保证或语义,也不需要支持中断正在进行的锁获取。需要一个实现来清楚地记录每种 * 锁定方法提供的语义和保证。它还必须遵守这个接口中定义的中断语义,只要支持锁获取中断:要么完全支 * 持,要么只支持方法入口。 * *

由于中断通常意味着取消,对中断的检查通常不频繁,所以实现可能更倾向于响应中断而不是正常的 * 方法返回。即使可以显示在另一个操作之后发生的中断可能已经解除了线程阻塞,这也是正确的。实现应 * 该记录这种行为。 * * @see ReentrantLock * @see Condition * @see ReadWriteLock * * @since 1.5 * @author Doug Lea */ public interface Lock { /** * 请求锁 * * 如果锁不可用,那么出于线程调度的目的,当前线程将被禁用,并处于休眠状态,直到获得锁为止。 * *

实现考虑 * * {@code Lock}实现可能能够检测到锁的错误使用,例如调用会导致死锁,并可能在这种情况下抛出 * (unchecked)异常。环境和异常类型必须由{@code Lock}实现记录。 */ void lock(); /** * 获取锁,除非当前线程是{@linkplain Thread#interrupt interrupted}。 * *

如果锁可用获取锁并立即返回。 * *

如果锁不可用,那么当前线程将出于线程调度的目的被禁用,并处于休眠状态,直到发生以下两种情况之一: * *

    *
  • 锁被当前线程获取;或者 *
  • 其他线程{@linkplain Thread#interrupt interrupts}当前线程,支持中断锁获取。 *
* *

如果当前线程: * *

    *
  • 在进入此方法时已设置其中断状态;或者 *
  • 是{@linkplain Thread#interrupt interrupted},当获取锁时,支持中断锁获取, *
* 则抛出{@link InterruptedException},清除当前线程的中断状态。 *

实现考虑 * *

在某些实现中中断锁获取的能力可能是不可能的,如果可能的话,这可能是一个昂贵的操作。程序员应该意识到情况 * 可能就是这样。当出现这种情况时,实现应该记录下来。 * *

实现更倾向于响应中断而不是正常的方法返回。 * *

{@code Lock}实现可能能够检测到锁的错误使用,例如调用会导致死锁,并可能在这种情况下抛出(unchecked)异常。 * 环境和异常类型必须由{@code Lock}实现记录。 * * @throw InterruptedException 如果当前线程在获取锁时被中断(并且支持中断锁获取)。 */ void lockInterruptibly() throws InterruptedException; /** * 仅当锁在调用时处于空闲状态时才获取锁。 * *

如果锁可用,获取锁,并立即返回值{@code true}。如果锁不可用,那么这个方法将立即返回值{@code false}。 * *

这个方法的一个典型用法是: * *

     *      Lock lock = ...;
     *      if (lock.tryLock()) {
     *          try {
     *              // 操作保护状态
     *          } finally {
     *              lock.unlock();
     *          }
     *      } else {
     *          // 执行选择操作
     *      }
     * 
* 这种用法确保锁在被获取时是解锁的,如果没有获取锁,则不会尝试解锁。 * * @return 如果获取到锁,返回{@code true},其他情况返回{@code false} */ boolean tryLock(); /** * 如果锁在给定的等待时间内是空闲的,并且当前线程不是{@linkplain Thread#interrupt interrupted},则获取该锁。 * *

如果锁可用,该方法立即返回值{@code true}。如果锁不可用,那么出于线程调度的目的,当前线程将被禁用, * 并处于休眠状态,直到发生以下三种情况之一: * *

    *
  • 锁被当前线程获取;或者 *
  • 其他线程{@linkplain Thread#interrupt interrupts}当前线程,支持中断锁获取;或者 *
  • 指定的等待时间已经过了 *
* *

如果获得锁,则返回值{@code true}。 * *

如果当前线程: * *

    *
  • 在进入此方法时已设置其中断状态;或者 *
  • 是{@linkplain Thread#interrupt interrupted},当获取锁时,支持中断锁获取, *
* 否则抛出{@link InterruptedException},清除当前线程的中断状态。 * *

如果指定的等待时间过去,则返回值{@code false}。如果时间小于或等于零,则该方法根本不会等待。 * *

实现考虑 * *

在某些实现中中断锁获取的能力可能是不可能的,如果可能的话,这可能是一个昂贵的操作。程序员应该意识到情况可能就是这样。 * 当出现这种情况时,实现应该记录下来。 * *

实现更倾向于响应中断而不是正常的方法返回,或者报告超时。 * *

{@code Lock}实现可能能够检测到锁的错误使用,例如调用会导致死锁,并可能在这种情况下抛出(unchecked)异常。 * 环境和异常类型必须由{@code Lock}实现记录。 * * @param time 等待锁的最大时间 * @param unit {@code time}参数的时间单位 * @return 如果获得锁,返回{@code true},如果在获得锁之前等待时间超时,则返回{@code false} * * @throws InterruptedException 如果请求锁的时候,当前线程被中断(并且锁支持捕获中断) */ boolean tryLock(long time, java.util.concurrent.TimeUnit unit) throws InterruptedException; /** * 释放锁 * *

实现考虑 * *

{@code Lock}实现通常会对哪个线程可以释放锁施加限制(通常只有锁的持有者才能释放锁),如果违反了这个限制, * 可能会抛出(unchecked)异常。任何限制和异常类型都必须由{@code Lock}实现记录。 */ void unlock(); /** * 返回绑定到这个{@code Lock}实例的一个新的{@link Condition}实例。 * *

在等待条件之前,锁必须由当前线程持有。调用{@link Condition#await()}将在等待之前自动释放锁, * 并在等待返回之前重新获取锁。 * *

实现考虑 * *

{@link Condition}实例的确切操作依赖于{@code Lock}实现,必须由该实现记录。 * * @return 这个{@code Lock}实例的一个新的{@link Condition}实例 * @throws UnsupportedOperationException 如果这个{@code Lock}实现不支持条件 */ Condition newCondition(); }

你可能感兴趣的:(Lock接口源代码分析)