1.什么是死鎖
在編寫多線程的時(shí)候,必須要注意資源的使用問題,如果兩個(gè)或多個(gè)線程分別擁有不同的資源捌肴,
而同時(shí)又需要對(duì)方釋放資源才能繼續(xù)運(yùn)行時(shí),就會(huì)發(fā)生死鎖藕咏。
簡(jiǎn)單來說:死鎖就是當(dāng)一個(gè)或多個(gè)進(jìn)程都在等待系統(tǒng)資源状知,而資源本身又被占用時(shí),所產(chǎn)生的一種狀態(tài)侈离。
造成死鎖的原因:
多個(gè)線程競(jìng)爭(zhēng)共享資源试幽,由于資源被占用,資源不足或進(jìn)程推進(jìn)順序不當(dāng)?shù)仍蛟斐删€程處于永久阻塞狀態(tài)卦碾,從而引發(fā)死鎖
2.死鎖產(chǎn)生的條件
當(dāng)然死鎖的產(chǎn)生是必須要滿足一些特定條件的:
- 互斥條件:進(jìn)程對(duì)于所分配到的資源具有排它性,即一個(gè)資源只能被一個(gè)進(jìn)程占用起宽,直到被該進(jìn)程釋放
- 請(qǐng)求和保持條件:一個(gè)進(jìn)程因請(qǐng)求被占用資源而發(fā)生阻塞時(shí)洲胖,對(duì)已獲得的資源保持不放。
- 不剝奪條件:任何一個(gè)資源在沒被該進(jìn)程釋放之前坯沪,任何其他進(jìn)程都無法對(duì)他剝奪占用
- 循環(huán)等待條件:當(dāng)發(fā)生死鎖時(shí)绿映,所等待的進(jìn)程必定會(huì)形成一個(gè)環(huán)路(類似于死循環(huán)),造成永久阻塞
3.死鎖代碼
package com.auncle.test;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.BaseRowModel;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.auncle.bean.UserBean;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* Created by 楊海濤
*
* @project:test
* @date:2019/4/22
*/
public class Auncle {
public static void main(String[] args) {
DeadLockThread deadlock1 = new DeadLockThread();
DeadLockThread deadlock2 = new DeadLockThread();
deadlock1.flag = true;
deadlock2.flag = false;
Thread thread1 = new Thread(deadlock1);
Thread thread2 = new Thread(deadlock2);
thread1.start();
thread2.start();
}
static class DeadLockThread implements Runnable {
private static final Object objectA = new Object();
private static final Object objectB = new Object();
private boolean flag;
@Override
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println("當(dāng)前線程 為:" + threadName + "\tflag = " + flag);
if (flag) {
synchronized (objectA) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(threadName + "已進(jìn)入同步代碼塊objectA腐晾,準(zhǔn)備進(jìn)入objectB");
synchronized (objectB) {
System.out.println(threadName + "已經(jīng)進(jìn)入同步代碼塊objectB");
}
}
} else {
synchronized (objectB) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(threadName + "已進(jìn)入同步代碼塊objectB叉弦,準(zhǔn)備進(jìn)入objectA");
synchronized (objectA) {
System.out.println(threadName + "已經(jīng)進(jìn)入同步代碼塊objectA");
}
}
}
}
}
}
4.避免死鎖
要預(yù)防和避免死鎖的發(fā)生,只需將上面所講到的4個(gè)條件破壞掉其中之一即可藻糖。
三種用于避免死鎖的技術(shù):
- 加鎖順序(線程按照一定的順序加鎖)
- 加鎖時(shí)限(線程嘗試獲取鎖的時(shí)候加上一定的時(shí)限淹冰,超過時(shí)限則放棄對(duì)該鎖的請(qǐng)求,并釋放自己占有的鎖)
- 死鎖檢測(cè)