Module java.base

Interface Lock

所有已知的实现类:
ReentrantLock, ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock

public interface Lock
Lock实现提供比使用synchronized方法和语句更广泛的锁定操作。它们允许更灵活的结构化,可能具有完全不同的属性,并且可能支持多个关联的Condition对象。

锁是控制多个线程对共享资源访问的工具。通常,锁提供对共享资源的独占访问:一次只有一个线程可以获取锁,并且所有对共享资源的访问都要求首先获取锁。然而,一些锁可能允许对共享资源的并发访问,例如ReadWriteLock的读锁。

使用synchronized方法或语句提供对与每个对象关联的隐式监视器锁的访问,但是强制所有锁的获取和释放以块结构方式发生:当获取多个锁时,它们必须以相反的顺序释放,并且所有锁必须在获取它们的同一词法范围内释放。

虽然synchronized方法和语句的作用域机制使得使用监视器锁更容易,有助于避免涉及锁的许多常见编程错误,但有时您需要以更灵活的方式使用锁。例如,一些用于遍历并发访问的数据结构的算法需要使用“递进锁定”或“链锁定”:您获取节点A的锁,然后节点B的锁,然后释放A并获取C,然后释放B并获取D,依此类推。 Lock接口的实现通过允许在不同范围内获取和释放锁,并允许以任何顺序获取和释放多个锁,从而使得可以使用这种技术。

这种增加的灵活性带来了额外的责任。不具有块结构锁定会导致synchronized方法和语句中自动释放锁的缺失。在大多数情况下,应使用以下习语:

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

Lock实现通过提供尝试非阻塞获取锁(tryLock())、可以中断的获取锁(lockInterruptibly())和可以超时的获取锁(tryLock(long, TimeUnit))等功能,提供了比使用synchronized方法和语句更多的功能。

Lock类还可以提供与隐式监视器锁完全不同的行为和语义,例如保证排序、非可重入使用或死锁检测。如果实现提供了这种专门的语义,那么实现必须记录这些语义。

请注意,Lock实例只是普通对象,它们本身可以作为synchronized语句中的目标使用。获取Lock实例的监视器锁与调用该实例的任何lock()方法之间没有指定的关系。建议避免混淆,除了在其自己的实现中使用Lock实例外,永远不要以这种方式使用Lock实例。

除非另有说明,否则将任何参数传递为null值将导致抛出NullPointerException

内存同步

所有Lock实现必须强制执行与内置监视器锁提供的相同的内存同步语义,如《Java语言规范》第17章所述:

  • 成功的lock操作具有与成功的Lock操作相同的内存同步效果。
  • 成功的unlock操作具有与成功的Unlock操作相同的内存同步效果。
不成功的锁定和解锁操作以及可重入的锁定/解锁操作不需要任何内存同步效果。

实现注意事项

锁获取的三种形式(可中断、不可中断和定时)可能在性能特征、排序保证或其他实现特性上有所不同。此外,在给定的Lock类中,可能无法中断对锁的进行中获取。因此,实现不需要为所有三种锁获取形式定义完全相同的保证或语义,也不需要支持对进行中的锁获取进行中断。实现必须清楚地记录每个锁定方法提供的语义和保证。它还必须遵守此接口中定义的中断语义,以支持锁获取的中断:这要么是完全支持,要么仅在方法进入时支持。

由于中断通常意味着取消,并且对中断的检查通常不频繁,因此实现可以更倾向于响应中断而不是正常方法返回。即使可以证明中断发生在另一个操作可能解除线程阻塞之后,实现也应记录此行为。

参见Java语言规范:
17.4 内存模型
自JDK版本:
1.5
参见:
  • Method Summary

    Modifier and Type
    Method
    Description
    void
    lock()
    获取锁。
    void
    获取锁,除非当前线程被中断
    返回一个绑定到此Lock实例的新Condition实例。
    boolean
    仅在调用时锁是空闲状态时才获取锁。
    boolean
    tryLock(long time, TimeUnit unit)
    在给定等待时间内,仅当锁是空闲状态且当前线程未被中断时才获取锁。
    void
    unlock()
    释放锁。
  • Method Details

    • lock

      void lock()
      获取锁。

      如果锁不可用,则当前线程将因线程调度目的而被禁用,并处于休眠状态,直到获取锁为止。

      实现注意事项

      Lock实现可能能够检测锁的错误使用,例如可能导致死锁的调用,并且在这种情况下可能会抛出(未检查的)异常。这种情况和异常类型必须由该Lock实现记录。

    • lockInterruptibly

      void lockInterruptibly() throws InterruptedException
      获取锁,除非当前线程被中断

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

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

      • 当前线程获取锁;或
      • 其他线程中断当前线程,并且支持锁获取的中断。

      如果当前线程:

      • 在进入此方法时设置了中断状态;或
      • 在获取锁时被中断,并且支持锁获取的中断,
      那么将抛出InterruptedException,并清除当前线程的中断状态。

      实现注意事项

      在某些实现中,可能无法中断锁获取操作,即使可能也是昂贵的操作。程序员应意识到这种情况。实现应记录这种情况。

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

      Lock实现可能能够检测锁的错误使用,例如可能导致死锁的调用,并且在这种情况下可能会抛出(未检查的)异常。这种情况和异常类型必须由该Lock实现记录。

      抛出:
      InterruptedException - 如果当前线程在获取锁时被中断(并且支持锁获取的中断)
    • tryLock

      boolean tryLock()
      仅在调用时锁是空闲状态时才获取锁。

      如果锁可用,则获取锁并立即返回值true。如果锁不可用,则此方法将立即返回值false

      此方法的典型用法习惯是:

       
       Lock lock = ...;
       if (lock.tryLock()) {
         try {
           // 操作受保护的状态
         } finally {
           lock.unlock();
         }
       } else {
         // 执行替代操作
       }
      此用法确保如果已获取锁,则解锁锁,并且如果未获取锁,则不尝试解锁锁。
      返回:
      如果获取了锁则返回true,否则返回false
    • tryLock

      boolean tryLock(long time, TimeUnit unit) throws InterruptedException
      获取锁,如果在给定的等待时间内锁是空闲的,并且当前线程尚未被中断

      如果锁可用,则此方法立即返回值true。如果锁不可用,则当前线程变为禁用以进行线程调度,并处于休眠状态,直到发生以下三种情况之一:

      • 锁被当前线程获取;或
      • 其他线程中断当前线程,并且支持中断锁获取;或
      • 指定的等待时间过去

      如果锁被获取,则返回值为true

      如果当前线程:

      • 在进入此方法时已设置了中断状态;或
      • 在获取锁时被中断,并且支持中断锁获取,
      则会抛出InterruptedException,并清除当前线程的中断状态。

      如果指定的等待时间过去,则返回值为false。如果时间小于或等于零,则该方法将根本不等待。

      实现注意事项

      在某些实现中,中断锁获取的能力可能是不可能的,如果可能的话,可能是一个昂贵的操作。程序员应该意识到这种情况。实现应该在这种情况下进行文档记录。

      实现可以优先响应中断而不是正常方法返回,或报告超时。

      Lock实现可能能够检测锁的错误使用,例如会导致死锁的调用,并且在这种情况下可能会抛出(未经检查的)异常。这种情况和异常类型必须由该Lock实现进行文档记录。

      参数:
      time - 等待锁的最长时间
      unit - time参数的时间单位
      返回:
      如果获取了锁,则返回true,如果在获取锁之前等待时间已过,则返回false
      抛出:
      InterruptedException - 如果当前线程在获取锁时被中断(并且支持中断锁获取)
    • unlock

      void unlock()
      释放锁。

      实现注意事项

      Lock实现通常会对哪个线程可以释放锁施加限制(通常只有锁的持有者可以释放它),如果违反了限制,则可能会抛出(未经检查的)异常。任何限制和异常类型必须由该Lock实现进行文档记录。

    • newCondition

      Condition newCondition()
      返回绑定到此Lock实例的新Condition实例。

      在等待条件之前,当前线程必须持有锁。调用Condition.await()将在等待之前原子性地释放锁,并在等待返回之前重新获取锁。

      实现注意事项

      Condition实例的确切操作取决于Lock实现,并必须由该实现进行文档记录。

      返回:
      Lock实例的新Condition实例
      抛出:
      UnsupportedOperationException - 如果此Lock实现不支持条件