JAVA死鎖的寫法

在java開發中,避免不了要加鎖控制程序邏輯,但加鎖有可能致使死鎖,形成線程永遠卡死在等待釋放鎖,後面的代碼得不到執行; 
在java裏,通常是經過synchronized關鍵字加鎖,在jdk1.5版本中新增了Lock接口顯示的加鎖,本文討論用這兩種方式實現死鎖; 
方式一:java

public static void main(String[] args) { Object lock1 = new Object(); Object lock2 = new Object(); ExecutorService service = Executors.newCachedThreadPool(); service.execute(() ->{ while (true){ synchronized (lock2){ synchronized (lock1){ System.out.println("Thread1"); } } } }); service.execute(() ->{ while (true){ synchronized (lock1){ synchronized (lock2){ System.out.println("Thread2"); } } } }); service.shutdown(); }

 

上面的代碼開啓了兩個線程,兩個線程都循環打印字符串,正常來講兩個線程都會不斷打印,但這裏出現了死鎖,致使兩個線程都會打印中止,邏輯分析:兩個線程執行到某一時刻,線程一執行到synchronized (lock2){這一句,得到了對象lock2上的鎖,線程二執行到synchronized (lock1){這一句,得到了對象lock1上的鎖,接下來,線程一須要執行synchronized (lock1){這一句嘗試獲取lock1的鎖,因爲lock1的鎖被線程二佔用,線程一等待線程二釋放lock1的鎖,這時線程二須要執行synchronized (lock2){這一句,嘗試獲取lock2上的鎖,因爲lock2上的鎖被線程一佔用,線程二等待線程一釋放lock2上的鎖,這樣,兩個線程互相等待釋放鎖,致使兩個線程永遠沒法執行後面的代碼,致使死鎖; 
方式二:ide

static final Lock LOCK1 = new ReentrantLock(); static final Lock LOCK2 = new ReentrantLock(); public static void main(String[] args) { ExecutorService service = Executors.newCachedThreadPool(); service.execute(new PrintTask1(1)); service.execute(new PrintTask2(2)); } static class PrintTask1 implements Runnable{ private int id = -1; public PrintTask1(int i){ id = i; } @Override public void run() { while (true){ LOCK1.lock(); LOCK2.lock(); System.out.println("" + id); LOCK2.unlock(); LOCK1.unlock(); } } } static class PrintTask2 implements Runnable{ private int id = -1; public PrintTask2(int i){ id = i; } @Override public void run() { while (true){ LOCK2.lock(); LOCK1.lock(); System.out.println("" + id); LOCK2.unlock(); LOCK1.unlock(); } } }

 

方式二的代碼屬於顯示加鎖,使用了jdk1.5新增的Lock接口,與方式一相似,當兩個線程執行到某一時刻,線程一執行了LOCK1.lock()得到了LOCK1鎖,線程二執行了LOCK2.lock()得到了LOCK2鎖,接下來兩個線程又要互相等待對方釋放鎖,致使死鎖。spa

相關文章
相關標籤/搜索