上文講到synchronized關鍵字在多線程中的使用,既然用到了鎖,就會有出現死鎖的狀況。一個線程得到鎖,若是其餘線程也想得到一樣的鎖就會阻塞住,等待鎖的釋放。若是線程A已經得到鎖1,還要得到鎖2,同時線程B已經得到鎖2,還要得到鎖1,那麼線程A和B就會一直阻塞住。java
依照慣例先舉個例子:多線程
public class Test { public static void main(String[] args) throws InterruptedException { Object lock1 = new Object(); Object lock2 = new Object(); Thread t1 = new Thread(new Test().new Tt1(lock1, lock2)); Thread t2 = new Thread(new Test().new Tt2(lock1, lock2)); t1.start(); t2.start(); } class Tt1 implements Runnable{ private Object lock1; private Object lock2; public Tt1(Object lock1,Object lock2) { this.lock1 = lock1; this.lock2 = lock2; } @Override public void run() { synchronized (lock1) { System.out.println(this.getClass()+"-------1"); try { Thread.sleep(1000); synchronized (lock2) { System.out.println(this.getClass()+"-------2"); } } catch (InterruptedException e) { e.printStackTrace(); } } } } class Tt2 implements Runnable{ private Object lock1; private Object lock2; public Tt2(Object lock1,Object lock2) { this.lock1 = lock1; this.lock2 = lock2; } @Override public void run() { synchronized (lock2) { System.out.println(this.getClass()+"-------1"); try { Thread.sleep(1000); synchronized (lock1) { System.out.println(this.getClass()+"-------2"); } } catch (InterruptedException e) { e.printStackTrace(); } } } } }
執行結果:ide
class Test$Tt1-------1 class Test$Tt2-------1
2個線程都只執行到了第一步,就沒有往下執行,都處於了阻塞狀態,這就是死鎖。this
死鎖問題並非一個容易被發現和定位的問題,若是系統出現死鎖問題,該如何定位?spa
1.使用jps,查詢java虛擬機的pid
2.使用jstack打印堆棧線程
以Thread-1爲例介紹下每一部分的意思
1).Thread-1 線程名稱
2).prio=5 線程優先級
3).os_prio=0 本地的優先級
4).tid=0x000000001929b800 線程id
5).nid=0xfb34 本地的線程id
6)
java.lang.Thread.State: BLOCKED (on object monitor)
線程狀態處於阻塞
7) waiting to lock <0x00000000d5dd0c38> (a java.lang.Object)正在等待的鎖
8)locked <0x00000000d5dd0c48> (a java.lang.Object) 已獲取的鎖code
如今咱們能夠看到Thread-1和Thread-0都處於阻塞狀態,Thread-1獲取了‘0x00000000d5dd0c48’鎖,等待‘0x00000000d5dd0c38’鎖,而Thread-0則恰好相反。圖片
咱們已經知道了死鎖的造成和定位,再來說講如何避免:
1.儘可能在線程中不嵌套獲取多個資源,但你只需獲取一個時就不會出現死鎖、
2.若是不得不嵌套使用時,要多考慮嵌套的順序
3.死鎖是由於無限的阻塞等待,若是能有一個最大的等待時間就能夠解決這個問題。synchronized不具有這個功能,可是咱們可使用Lock類中的tryLock方法去嘗試獲取鎖,這個方法能夠指定一個超時時限,在等待超過該時限以後返回失敗信息資源