1、什麼是死鎖多線程
死鎖理解起來很簡單,就是一個字,堵,下面圖中擁堵的十字路口就能夠看作一個死鎖的狀態,四個方向的車都要往前走,可是十字路口只有一個,只能容許一個方向的車經過後,才能讓另外一個方向的車經過。ide
在多線程中,四個方向的車流就能夠看作4個線程,而十字路口能夠看作一個資源對象,四個線程都要佔有它,會致使程序沒法正常的運行,這就叫死鎖,是否是很容易理解呢。post
用比較官方的解釋死鎖的話,就是經典的四大條件學習
一、互斥使用,即當資源被一個線程使用(佔有)時,別的線程不能使用spa
二、不可搶佔,資源請求者不能強制從資源佔有者手中奪取資源,資源只能由資源佔有者主動釋放。線程
三、請求和保持,即當資源請求者在請求其餘的資源的同時保持對原有資源的佔有。code
四、循環等待,即存在一個等待隊列:P1佔有P2的資源,P2佔有P3的資源,P3佔有P1的資源。這樣就造成了一個等待環路。視頻
當上述四個條件都成立的時候,便造成死鎖。固然,死鎖的狀況下若是打破上述任何一個條件,即可讓死鎖消失。對象
2、建立死鎖案例教程
public class DeadLock { public static String r1="r1"; public static String r2="r2"; public static void main(String[] args) { Runable1 runable1=new Runable1(); Runable2 runable2=new Runable2(); Thread thread1=new Thread(runable1); Thread thread2=new Thread(runable2); thread1.start(); thread2.start(); } } class Runable1 implements Runnable{ @Override public void run() { try { (DeadLock.r1) { System.out.println("r1的synchronized鎖住r1"); Thread.sleep(3000); synchronized (DeadLock.r2) { System.out.println("拿不到r2略略略"); Thread.sleep(60 * 1000); } System.out.println("被鎖住了,沒法打印"); } }catch (Exception e) { e.printStackTrace(); } } } class Runable2 implements Runnable{ @Override public void run() { try { synchronized (DeadLock.r2){ System.out.println("synchronized鎖住r2"); Thread.sleep(3000); synchronized (DeadLock.r1){ System.out.println("拿不到r1略略略"); Thread.sleep(60 * 1000); } System.out.println("被鎖住了,沒法打印"); } }catch (Exception e){ e.printStackTrace(); } } } //運行結果 r1的synchronized鎖住r1 synchronized鎖住r2 複製代碼
在上面這個案例中,先建立了兩個資源對象r1和r2,而後建立了兩個線程類Runable1和Runable2,用synchronized方法去給資源添加鎖,使得兩個線程在執行完run方法以前都不會釋放資源對象r1和r2,(synchronized方法的做用就是一個同步鎖,代碼中放入synchronized括號中的資源在線程結束前都不會釋放,也就不能被其餘線程使用)以後用sleep方法讓線程阻塞(sleep(3000)的做用是是給線程能鎖住機會,sleep(60*1000)的做用是讓線程阻塞),這樣就形成了死鎖的現象,致使後面的語句沒法打印出來。
3、如何解決死鎖問題
1.在寫多線程操做時,最好不要一次鎖定多個對象,這樣就不會致使死鎖了。修改後的代碼以下。
public class DeadLock { public static String r1="r1"; public static String r2="r2"; public static void main(String[] args) { Runable1 runable1=new Runable1(); Runable2 runable2=new Runable2(); Thread thread1=new Thread(runable1); Thread thread2=new Thread(runable2); thread1.start(); thread2.start(); } } class Runable1 implements Runnable{ @Override public void run() { try { synchronized (DeadLock.r1) { System.out.println("r1的synchronized鎖住r1"); Thread.sleep(3000); System.out.println("拿到r2"); Thread.sleep(3000); System.out.println("解鎖了,能夠打印"); } }catch (Exception e) { e.printStackTrace(); } } } class Runable2 implements Runnable{ @Override public void run() { try { synchronized (DeadLock.r2){ System.out.println("synchronized鎖住r2"); Thread.sleep(3000); System.out.println("拿到r1"); Thread.sleep(3000); System.out.println("解鎖了,能夠打印"); } }catch (Exception e){ e.printStackTrace(); } } } //運行結果 r1的synchronized鎖住r1 synchronized鎖住r2 拿到r2 拿到r1 解鎖了,能夠打印 解鎖了,能夠打印 複製代碼
2.若是業務場景須要一次鎖定多個資源對象,能夠根據資源的某個屬性或者hashCode值來作比較,定義鎖的前後順序,下面是一個經過hashCode來定義鎖前後順序的例子。
public class DeadLock { public static String r1="r1"; public static String r2="r2"; public static void main(String[] args) { Runable1 runable1=new Runable1(); Runable2 runable2=new Runable2(); Thread thread1=new Thread(runable1); Thread thread2=new Thread(runable2); thread1.start(); thread2.start(); } } class Runable1 implements Runnable{ @Override public void run() { try { if (DeadLock.r1.hashCode()>DeadLock.r2.hashCode()) { synchronized (DeadLock.r1) { System.out.println("Runable1的synchronized鎖住r1"); Thread.sleep(3000); synchronized (DeadLock.r2) { System.out.println("Runable1的synchronized鎖住r2"); Thread.sleep(3000); } System.out.println("解鎖了,能夠打印"); } }else{ synchronized (DeadLock.r2) { System.out.println("Runable1的synchronized鎖住r1"); Thread.sleep(3000); synchronized (DeadLock.r1) { System.out.println("Runable1的synchronized鎖住r2"); Thread.sleep(3000); } System.out.println("解鎖了,能夠打印"); } } }catch (Exception e) { e.printStackTrace(); } } } class Runable2 implements Runnable{ @Override public void run() { try { if (DeadLock.r1.hashCode()<DeadLock.r2.hashCode()) { synchronized (DeadLock.r2) { System.out.println("Runable2的synchronized鎖住r2"); Thread.sleep(3000); synchronized (DeadLock.r1) { System.out.println("Runable2的synchronized鎖住r1"); Thread.sleep(3000); } System.out.println("解鎖了,能夠打印"); } }else{ synchronized (DeadLock.r1) { System.out.println("Runable2的synchronized鎖住r1"); Thread.sleep(3000); synchronized (DeadLock.r2) { System.out.println("Runable2的synchronized鎖住r2"); Thread.sleep(3000); } System.out.println("解鎖了,能夠打印"); } } }catch (Exception e) { e.printStackTrace(); } } } //運行結果 Runable1的synchronized鎖住r1 Runable1的synchronized鎖住r2 解鎖了,能夠打印 Runable2的synchronized鎖住r1 Runable2的synchronized鎖住r2 解鎖了,能夠打印
參考:《2020最新Java基礎精講視頻教程和學習路線!》
連接:https://juejin.cn/post/694043...