轉載自:https://www.zhihu.com/question/36771163/answer/68974735
ReentrantLock 鎖有好幾種,除了常用的lock ,tryLock ,其中有個lockInterruptibly 。
先把API粘貼上來
關於中斷又是一段很長的敘述,先不談。
先看lock()方法
用eclipse對這個程序進行debug發現,即使子線程已經被打斷,但是子線程仍然在run,可見lock()方法並不關心線程是否被打斷,甚至說主線程已經運行完畢,子線程仍然在block().
而使用LockInterupptibly,則會響應中斷
如果將代碼改成這樣,那么將會在在阻塞之前已經中斷,此時再lockInterruptibly()也是會相應中斷異常的
先把API粘貼上來
lock
public void lock()
獲取鎖。
如果該鎖沒有被另一個線程保持,則獲取該鎖並立即返回,將鎖的保持計數設置為 1。
如果當前線程已經保持該鎖,則將保持計數加 1,並且該方法立即返回。
如果該鎖被另一個線程保持,則出於線程調度的目的,禁用當前線程,並且在獲得鎖之前,該線程將一
直處於休眠狀態,此時鎖保持計數被設置為 1。
指定者:
接口 Lock 中的 lock
lockInterruptibly
public void lockInterruptibly() throws InterruptedException
1)如果當前線程未被中斷,則獲取鎖。
2)如果該鎖沒有被另一個線程保持,則獲取該鎖並立即返回,將鎖的保持計數設置為 1。
3)如果當前線程已經保持此鎖,則將保持計數加 1,並且該方法立即返回。
4)如果鎖被另一個線程保持,則出於線程調度目的,禁用當前線程,並且在發生以下兩種情況之一以
前,該線程將一直處於休眠狀態:
1)鎖由當前線程獲得;或者
2)其他某個線程中斷當前線程。
5)如果當前線程獲得該鎖,則將鎖保持計數設置為 1。
如果當前線程:
1)在進入此方法時已經設置了該線程的中斷狀態;或者
2)在等待獲取鎖的同時被中斷。
則拋出 InterruptedException,並且清除當前線程的已中斷狀態。
6)在此實現中,因為此方法是一個顯式中斷點,所以要優先考慮響應中斷,而不是響應鎖的普通獲取或
重入獲取。
指定者: 接口 Lock 中的 lockInterruptibly
拋出: InterruptedException 如果當前線程已中斷。
tryLock public boolean tryLock()
僅在調用時鎖未被另一個線程保持的情況下,才獲取該鎖。
1)如果該鎖沒有被另一個線程保持,並且立即返回 true 值,則將鎖的保持計數設置為 1。
即使已將此鎖設置為使用公平排序策略,但是調用 tryLock() 仍將 立即獲取鎖(如果有可用的),
而不管其他線程當前是否正在等待該鎖。在某些情況下,此“闖入”行為可能很有用,即使它會打破公
平性也如此。如果希望遵守此鎖的公平設置,則使用 tryLock(0, TimeUnit.SECONDS)
,它幾乎是等效的(也檢測中斷)。
2)如果當前線程已經保持此鎖,則將保持計數加 1,該方法將返回 true。
3)如果鎖被另一個線程保持,則此方法將立即返回 false 值。
指定者:
接口 Lock 中的 tryLock
返回:
如果鎖是自由的並且被當前線程獲取,或者當前線程已經保持該鎖,則返回 true;否則返回
false
關於中斷又是一段很長的敘述,先不談。
1)lock(), 拿不到lock就不罷休,不然線程就一直block。 比較無賴的做法。
2)tryLock(),馬上返回,拿到lock就返回true,不然返回false。 比較瀟灑的做法。
帶時間限制的tryLock(),拿不到lock,就等一段時間,超時返回false。比較聰明的做法。
3)lockInterruptibly()就稍微難理解一些。
先說說線程的打擾機制,每個線程都有一個 打擾 標志。這里分兩種情況,
1. 線程在sleep或wait,join, 此時如果別的進程調用此進程的 interrupt()方法,此線程會被喚醒並被要求處理InterruptedException;(thread在做IO操作時也可能有類似行為,見java thread api)
2. 此線程在運行中, 則不會收到提醒。但是 此線程的 “打擾標志”會被設置, 可以通過isInterrupted()查看並 作出處理。
lockInterruptibly()和上面的第一種情況是一樣的, 線程在請求lock並被阻塞時,如果被interrupt,則“此線程會被喚醒並被要求處理InterruptedException”。並且如果線程已經被interrupt,再使用lockInterruptibly的時候,此線程也會被要求處理interruptedException
先看lock()方法
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author 作者 E-mail:
* @version 創建時間:2015-10-23 下午01:47:03 類說明
*/
public class TestLock
{
// @Test
public void test() throws Exception
{
final Lock lock = new ReentrantLock();
lock.lock();
Thread t1 = new Thread(new Runnable()
{
@Override
public void run()
{
lock.lock();
System.out.println(Thread.currentThread().getName() + " interrupted.");
}
},"child thread -1");
t1.start();
Thread.sleep(1000);
t1.interrupt();
Thread.sleep(1000000);
}
public static void main(String[] args) throws Exception
{
new TestLock().test();
}
}
用eclipse對這個程序進行debug發現,即使子線程已經被打斷,但是子線程仍然在run,可見lock()方法並不關心線程是否被打斷,甚至說主線程已經運行完畢,子線程仍然在block().

而使用LockInterupptibly,則會響應中斷
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author 作者 E-mail:
* @version 創建時間:2015-10-23 下午01:53:10 類說明
*/
public class TestLockInterruptibly
{
// @Test
public void test3() throws Exception
{
final Lock lock = new ReentrantLock();
lock.lock();
Thread t1 = new Thread(new Runnable()
{
@Override
public void run()
{
try
{
lock.lockInterruptibly();
}
catch(InterruptedException e)
{
System.out.println(Thread.currentThread().getName() + " interrupted.");
}
}
}, "child thread -1");
t1.start();
Thread.sleep(1000);
t1.interrupt();
Thread.sleep(1000000);
}
public static void main(String[] args) throws Exception
{
new TestLockInterruptibly().test3();
}
}


try{
Thread.sleep(2000);
lock.lockInterruptibly();
}catch(InterruptedException e){
System.out.println(Thread.currentThread().getName()+" interrupted.");
}
t1.start();
t1.interrupt();
Thread.sleep(1000000);
如果將代碼改成這樣,那么將會在在阻塞之前已經中斷,此時再lockInterruptibly()也是會相應中斷異常的