等待線程由于喚醒線程所需要的條件 永遠無法成立導(dǎo)致線程一直無法處于RUNNABLE狀態(tài),我們就稱這個線程被鎖死。
雖然死鎖與鎖死表現(xiàn)出來都是線程等待,無法繼續(xù)完成任務(wù),但是產(chǎn)生的條件是不同的,即使在不可能產(chǎn)生死鎖的情況下也可能出現(xiàn)鎖死,所以不能使用對付死鎖的辦法來解決鎖死問題。
鎖死包括信號丟失鎖死和嵌套監(jiān)視器鎖死。
信號丟失鎖死的典型案例是等待線程執(zhí)行Object.wait()/Condition.await()前沒有對保護條件進行判斷,可能沒有其他的線程更新相應(yīng)的保護條件涉及的變量使其成立并通知線程,使得線程一直處于等待狀態(tài)。
嵌套監(jiān)視鎖死是嵌套鎖導(dǎo)致線程永遠無法被喚醒,如有等待方法:
public void waitMethod(){
synchronized( lock1) {
synchronized( lock2){
while( 條件 ){
lock2.wait();
}
}
//....
}
}
還有喚醒 方法如下:
public void notifyMethod(){
synchronized( lock1) {
synchronized( lock2){
lock2.notifyAll();
}
}
}
package com.wkcto.threadactivity.lockdead;
import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
/**
* 演示嵌套監(jiān)視鎖死
*/
public class Test {
public static void main(String[] args) {
//創(chuàng)建線程,調(diào)用 putData方法向隊列中存儲數(shù)據(jù)
new Thread(new Runnable() {
@Override
public void run() {
int i = 0;
while ( i-- < 1000){
putData("data--" + i);
try {
Thread.sleep(new Random().nextInt(50));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
//創(chuàng)建線程調(diào)用getData方法從隊列中取數(shù)據(jù)
new Thread(new Runnable() {
@Override
public void run() {
while (true){
getData();
}
}
}).start();
/*
程序運行后,不管是putData()方法還是getData()方法獲得鎖的順序是相同,不可能產(chǎn)生死鎖
運行后出現(xiàn)等待的情況,是因為嵌套監(jiān)視鎖死導(dǎo)致的等待
*/
}
//定義阻塞隊列
private static final BlockingQueue QUEUE = new ArrayBlockingQueue<>(10);
//定義方法向隊列中添加數(shù)據(jù)
public static synchronized void putData(String data){
//在同步代碼塊(臨界區(qū))中,調(diào)用阻塞隊列QUEUE的put()/take()這些阻塞方法,可能會導(dǎo)致嵌套監(jiān)視鎖死
try {
QUEUE.put(data);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//定義方法從隊列中取數(shù)據(jù)
public static synchronized void getData(){
try {
String data = QUEUE.take();
System.out.println("取出數(shù)據(jù): " + data);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}