bilibili-Java并发学习笔记6 Lock锁
基于 java 1.8.0
/**
* Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。此实现允许更灵活的结构,可以具有差别很大的属性,可以支持多个相关的 Condition 对象。
* 锁是控制多个线程对共享资源进行访问的工具。通常,锁提供了对共享资源的独占访问。一次只能有一个线程获得锁,对共享资源的所有访问都需要首先获得锁。不过,某些锁可能允许对共享资源并发访问,如 ReadWriteLock 的读取锁。
* synchronized 方法或语句的使用提供了对与每个对象相关的隐式监视器锁的访问,但却强制所有锁获取和释放均要出现在一个块结构中:当获取了多个锁时,它们必须以相反的顺序释放,且必须在与所有锁被获取时相同的词法范围内释放所有锁。
* 虽然 synchronized 方法和语句的范围机制使得使用监视器锁编程方便了很多,而且还帮助避免了很多涉及到锁的常见编程错误,但有时也需要以更为灵活的方式使用锁。例如,某些遍历并发访问的数据结果的算法要求使用 "hand-over-hand" 或 "chain locking":获取节点 A 的锁,然后再获取节点 B 的锁,然后释放 A 并获取 C,然后释放 B 并获取 D,依此类推。Lock 接口的实现允许锁在不同的作用范围内获取和释放,并允许以任何顺序获取和释放多个锁,从而支持使用这种技术。
* 随着灵活性的增加,也带来了更多的责任。不使用块结构锁就失去了使用 synchronized 方法和语句时会出现的锁自动释放功能。在大多数情况下,应该使用以下语句:
Lock l = ...;
l.lock();
try {
// access the resource protected by this lock
} finally {
l.unlock();
}
* 锁定和取消锁定出现在不同作用范围中时,必须谨慎地确保保持锁定时所执行的所有代码用 try-finally 或 try-catch 加以保护,以确保在必要时释放锁。
* Lock 实现提供了使用 synchronized 方法和语句所没有的其他功能,包括提供了一个非块结构的获取锁尝试 (tryLock())、一个获取可中断锁的尝试 (lockInterruptibly()) 和一个获取超时失效锁的尝试 (tryLock(long, TimeUnit))。
* Lock 类还可以提供与隐式监视器锁完全不同的行为和语义,如保证排序、非重入用法或死锁检测。如果某个实现提供了这样特殊的语义,则该实现必须对这些语义加以记录。
* 注意,Lock 实例只是普通的对象,其本身可以在 synchronized 语句中作为目标使用。获取 Lock 实例的监视器锁与调用该实例的任何 lock() 方法没有特别的关系。为了避免混淆,建议除了在其自身的实现中之外,决不要以这种方式使用 Lock 实例。
* 除非另有说明,否则为任何参数传递 null 值都将导致抛出 NullPointerException。
* ---
* 内存同步
* 所有 Lock 实现都必须 实施与内置监视器锁提供的相同内存同步语义,如 [The Java Language Specification, Third Edition (17.4 Memory Model)](https://docs.oracle.com/javase/specs/jls/se6/html/memory.html#17.4) 中所描述的:
* - 成功的 lock 操作与成功的 Lock 操作具有同样的内存同步效应。
* - 成功的 unlock 操作与成功的 Unlock 操作具有同样的内存同步效应。
* 不成功的锁定与取消锁定操作以及重入锁定/取消锁定操作都不需要任何内存同步效果。
* ---
* 实现注意事项
* 三种形式的锁获取(可中断、不可中断和定时)在其性能特征、排序保证或其他实现质量上可能会有所不同。而且,对于给定的 Lock 类,可能没有中断正在进行的 锁获取的能力。因此,并不要求实现为所有三种形式的锁获取定义相同的保证或语义,也不要求其支持中断正在进行的锁获取。实现必需清楚地对每个锁定方法所提供的语义和保证进行记录。还必须遵守此接口中定义的中断语义,以便为锁获取中断提供支持:完全支持中断,或仅在进入方法时支持中断。
* 由于中断通常意味着取消,而通常又很少进行中断检查,因此,相对于普通方法返回而言,实现可能更喜欢响应某个中断。即使出现在另一个操作后的中断可能会释放线程锁时也是如此。实现应记录此行为。
*
* @see ReentrantLock
* @see Condition
* @see ReadWriteLock
*
* @since 1.5
* @author Doug Lea
*/
public interface Lock {
/**
* Acquires the lock.
* 获取锁。
*
* If the lock is not available then the current thread becomes
* disabled for thread scheduling purposes and lies dormant until the
* lock has been acquired.
* 如果锁不可用,出于线程调度目的,将禁用当前线程,并且在获得锁之前,该线程将一直处于休眠状态。
*
*
Implementation Considerations
* 实现注意事项
*
*
A {@code Lock} implementation may be able to detect erroneous use
* of the lock, such as an invocation that would cause deadlock, and
* may throw an (unchecked) exception in such circumstances. The
* circumstances and the exception type must be documented by that
* {@code Lock} implementation.
* Lock 实现可能能够检测到锁的错误使用,比如会导致死锁的调用,在那种环境下还可能抛出一个 (unchecked) 异常。Lock 实现必须对环境和异常类型进行记录。
*/
void lock();
/**
* Acquires the lock unless the current thread is
* {@linkplain Thread#interrupt interrupted}. 如果当前线程未被中断,则获取锁。
*
* Acquires the lock if it is available and returns immediately. 如果锁可用,则获取锁,并立即返回。
*
*
If the lock is not available then the current thread becomes
* disabled for thread scheduling purposes and lies dormant until
* one of two things happens: 如果锁不可用,出于线程调度目的,将禁用当前线程,并且在发生以下两种情况之一以前,该线程将一直处于休眠状态:
*
*
* - The lock is acquired by the current thread; or 锁由当前线程获得;或者
*
- Some other thread {@linkplain Thread#interrupt interrupts} the
* current thread, and interruption of lock acquisition is supported. 其他某个线程中断当前线程,并且支持对锁获取的中断。
*
*
* If the current thread: 如果当前线程
*
* - has its interrupted status set on entry to this method; or 在进入此方法时已经设置了该线程的中断状态;或者
*
- is {@linkplain Thread#interrupt interrupted} while acquiring the
* lock, and interruption of lock acquisition is supported, 在获取锁时被中断,并且支持对锁获取的中断,
*
* then {@link InterruptedException} is thrown and the current thread's
* interrupted status is cleared. 则将抛出 InterruptedException,并清除当前线程的已中断状态。
*
* Implementation Considerations 实现注意事项
*
*
The ability to interrupt a lock acquisition in some
* implementations may not be possible, and if possible may be an
* expensive operation. The programmer should be aware that this
* may be the case. An implementation should document when this is
* the case. 在某些实现中可能无法中断锁获取,即使可能,该操作的开销也很大。程序员应该知道可能会发生这种情况。在这种情况下,该实现应该对此进行记录。
*
*
An implementation can favor responding to an interrupt over
* normal method return. 相对于普通方法返回而言,实现可能更喜欢响应某个中断。
*
*
A {@code Lock} implementation may be able to detect
* erroneous use of the lock, such as an invocation that would
* cause deadlock, and may throw an (unchecked) exception in such
* circumstances. The circumstances and the exception type must
* be documented by that {@code Lock} implementation. Lock 实现可能可以检测锁的错误用法,例如,某个调用可能导致死锁,在特定的环境中可能抛出(未经检查的)异常。该 Lock 实现必须对环境和异常类型进行记录。
*
* @throws InterruptedException if the current thread is
* interrupted while acquiring the lock (and interruption
* of lock acquisition is supported) 如果在获取锁时,当前线程被中断(并且支持对锁获取的中断)。
*/
void lockInterruptibly() throws InterruptedException;
/**
* Acquires the lock only if it is free at the time of invocation. 仅在调用时锁为空闲状态才获取该锁。
*
* Acquires the lock if it is available and returns immediately
* with the value {@code true}.
* If the lock is not available then this method will return
* immediately with the value {@code false}. 如果锁可用,则获取锁,并立即返回值 true。如果锁不可用,则此方法将立即返回值 false。
*
*
A typical usage idiom for this method would be: 此方法的典型使用语句如下:
*
{@code
* Lock lock = ...;
* if (lock.tryLock()) {
* try {
* // manipulate protected state
* } finally {
* lock.unlock();
* }
* } else {
* // perform alternative actions
* }}
*
* This usage ensures that the lock is unlocked if it was acquired, and
* doesn't try to unlock if the lock was not acquired. 此用法可确保如果获取了锁,则会释放锁,如果未获取锁,则不会试图将其释放。
*
* @return {@code true} if the lock was acquired and
* {@code false} otherwise 如果获取了锁,则返回 true;否则返回 false。
*/
boolean tryLock();
/**
* Acquires the lock if it is free within the given waiting time and the
* current thread has not been {@linkplain Thread#interrupt interrupted}. 如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁。
*
* If the lock is available this method returns immediately
* with the value {@code true}.
* If the lock is not available then
* the current thread becomes disabled for thread scheduling
* purposes and lies dormant until one of three things happens: 如果锁可用,则此方法将立即返回值 true。如果锁不可用,出于线程调度目的,将禁用当前线程,并且在发生以下三种情况之一前,该线程将一直处于休眠状态:
*
* - The lock is acquired by the current thread; or 锁由当前线程获得;或者
*
- Some other thread {@linkplain Thread#interrupt interrupts} the
* current thread, and interruption of lock acquisition is supported; or 其他某个线程中断当前线程,并且支持对锁获取的中断;或者
*
- The specified waiting time elapses 已超过指定的等待时间
*
*
* If the lock is acquired then the value {@code true} is returned. 如果获得了锁,则返回值 true。
*
*
If the current thread: 如果当前线程:
*
* - has its interrupted status set on entry to this method; or 在进入此方法时已经设置了该线程的中断状态;或者
*
- is {@linkplain Thread#interrupt interrupted} while acquiring
* the lock, and interruption of lock acquisition is supported, 在获取锁时被中断,并且支持对锁获取的中断,
*
* then {@link InterruptedException} is thrown and the current thread's
* interrupted status is cleared. 则将抛出 InterruptedException,并会清除当前线程的已中断状态。
*
* If the specified waiting time elapses then the value {@code false}
* is returned.
* If the time is
* less than or equal to zero, the method will not wait at all. 如果超过了指定的等待时间,则将返回值 false。如果 time 小于等于 0,该方法将完全不等待。
*
*
Implementation Considerations 实现注意事项
*
*
The ability to interrupt a lock acquisition in some implementations
* may not be possible, and if possible may
* be an expensive operation.
* The programmer should be aware that this may be the case. An
* implementation should document when this is the case. 在某些实现中可能无法中断锁获取,即使可能,该操作的开销也很大。程序员应该知道可能会发生这种情况。在这种情况下,该实现应该对此进行记录。
*
*
An implementation can favor responding to an interrupt over normal
* method return, or reporting a timeout. 相对于普通方法返回而言,实现可能更喜欢响应某个中断,或者报告出现超时情况。
*
*
A {@code Lock} implementation may be able to detect
* erroneous use of the lock, such as an invocation that would cause
* deadlock, and may throw an (unchecked) exception in such circumstances.
* The circumstances and the exception type must be documented by that
* {@code Lock} implementation. Lock 实现可能可以检测锁的错误用法,例如,某个调用可能导致死锁,在特定的环境中可能抛出(未经检查的)异常。该 Lock 实现必须对环境和异常类型进行记录。
*
* @param time the maximum time to wait for the lock 等待锁的最长时间
* @param unit the time unit of the {@code time} argument 参数 time 的时间单位
* @return {@code true} if the lock was acquired and {@code false}
* if the waiting time elapsed before the lock was acquired 如果获得了锁,则返回 true;如果在获取锁前超过了等待时间,则返回 false
*
* @throws InterruptedException if the current thread is interrupted
* while acquiring the lock (and interruption of lock
* acquisition is supported) 如果在获取锁时,当前线程被中断(并且支持对锁获取的中断)
*/
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
/**
* Releases the lock. 释放锁。
*
* Implementation Considerations
*
*
A {@code Lock} implementation will usually impose
* restrictions on which thread can release a lock (typically only the
* holder of the lock can release it) and may throw
* an (unchecked) exception if the restriction is violated.
* Any restrictions and the exception
* type must be documented by that {@code Lock} implementation.
* Lock 实现通常对哪个线程可以释放锁施加了限制(通常只有锁的保持者可以释放它),如果违背了这个限制,可能会抛出(未经检查的)异常。该 Lock 实现必须对所有限制和异常类型进行记录。
*/
void unlock();
/**
* Returns a new {@link Condition} instance that is bound to this
* {@code Lock} instance. 返回绑定到此 Lock 实例的新 Condition 实例。
*
* Before waiting on the condition the lock must be held by the
* current thread.
* A call to {@link Condition#await()} will atomically release the lock
* before waiting and re-acquire the lock before the wait returns. 在等待条件前,锁必须由当前线程保持。调用 Condition.await() 将在等待前以原子方式释放锁,并在等待返回前重新获取锁。
*
*
Implementation Considerations
*
*
The exact operation of the {@link Condition} instance depends on
* the {@code Lock} implementation and must be documented by that
* implementation. Condition 实例的具体操作依赖于 Lock 实现,并且该实现必须对此加以记录。
*
* @return A new {@link Condition} instance for this {@code Lock} instance 用于此 Lock 实例的新 Condition 实例
* @throws UnsupportedOperationException if this {@code Lock}
* implementation does not support conditions 如果此 Lock 实现不支持条件
*/
Condition newCondition();
}
public static void main(String[] args) {
Lock lock = new ReentrantLock();
lock.lock();
try {
// do something
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
Lock lock = new ReentrantLock();
if (lock.tryLock()) {
try {
// manipulate protected state
} finally {
lock.unlock();
}
} else {
// perform alternative actions
}
}
public static void main(String[] args) {
Lock lock = new ReentrantLock();
try {
if (lock.tryLock(3L, TimeUnit.SECONDS)) {
try {
// manipulate protected state
} finally {
lock.unlock();
}
} else {
// perform alternative actions
}
} catch (InterruptedException e) {
// log
}
}
package new_package.thread.p24;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockTest2 {
private Lock lock = new ReentrantLock();
public void method1() {
try {
lock.lock();
System.out.println("method1 invoke");
} finally {
// lock.unlock();
}
}
public void method2() {
try {
lock.lock();
System.out.println("method2 invoke");
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
LockTest2 lockTest2 = new LockTest2();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
lockTest2.method1();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
lockTest2.method2();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
package new_package.thread.p24;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockTest3 {
private Lock lock = new ReentrantLock();
public void method1(long time) {
try {
lock.lock();
System.out.println("method1 invoke");
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
} finally {
lock.unlock();
}
}
public void method2(long time) {
try {
if (lock.tryLock(800, TimeUnit.MILLISECONDS)) {
try {
System.out.println("method2 invoke");
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
} finally {
lock.unlock();
}
} else {
System.out.println("method2 not get lock");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
LockTest3 lockTest3 = new LockTest3();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
lockTest3.method1(2000);
}
}).start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
lockTest3.method2(2000);
}
}).start();
}
}
Lock 与 synchronized 的区别: