java實現死結的範例程式碼,java範例程式碼
什麼是死結
我們先看看這樣一個生活中的例子:在一條河上有一座橋,橋面較窄,只能容納一輛汽車通過,無法讓兩輛汽車並行。如果有兩輛汽車A和B分別由橋的兩端駛上該橋,則對於A車來說,它走過橋面左面的一段路(即佔有了橋的一部分資源),要想過橋還須等待B車讓出右邊的橋面,此時A車不能前進;對於B車來說,它走過橋面右邊的一段路(即佔有了橋的一部分資源),要想過橋還須等待A車讓出左邊的橋面,此時B車也不能前進。兩邊的車都不倒車,結果造成互相等待對方讓出橋面,但是誰也不讓路,就會無休止地等下去。這種現象就是死結。如果把汽車比做進程,橋面作為資源,那麽上述問題就描述為:進程A佔有資源R1,等待進程B佔有的資源Rr;進程B佔有資源Rr,等待進程A佔有的資源R1。而且資源R1和Rr只允許一個進程佔用,即:不允許兩個進程同時佔用。結果,兩個進程都不能繼續執行,若不採取其它措施,這種迴圈等待狀況會無限期持續下去,就發生了進程死結。
在電腦系統中,涉及軟體,硬體資源都可能發生死結。例如:系統中只有一台CD-ROM磁碟機和一台印表機,某一個進程佔有了CD-ROM磁碟機,又申請印表機;另一進程佔有了印表機,還申請CD-ROM。結果,兩個進程都被阻塞,永遠也不能自行解除。
所謂死結,是指多個進程迴圈等待它方佔有的資源而無限期地僵持下去的局面。很顯然,如果沒有外力的作用,那麽死結涉及到的各個進程都將永遠處於封鎖狀態。從上面的例子可以看出,電腦系統產生死結的根本原因就是資源有限且操作不當。即:一種原因是系統提供的資源太少了,遠不能滿足並發進程對資源的需求。這種競爭資源引起的死結是我們要討論的核心。例如:訊息是一種臨時性資源。某一時刻,進程A等待進程B發來的訊息,進程B等待進程C發來的訊息,而進程C又等待進程A發來的訊息。訊息未到,A,B,C三個進程均無法向前推進,也會發生進程通訊上的死結。另一種原因是由於進程推進順序不合適引發的死結。資源少也未必一定產生死結。就如同兩個人過獨木橋,如果兩個人都要先過,在獨木橋上僵持不肯後退,必然會應競爭資源產生死結;但是,如果兩個人上橋前先看一看有無對方的人在橋上,當無對方的人在橋上時自己才上橋,那麽問題就解決了。所以,如果程式設計得不合理,造成進程推進的順序不當,也會出現死結。
死結
只有當t1線程佔用o1且正好也需要o2,t2此時佔用o2且正好也需要o1的時候才會出現死結,(類似於2個人拿著兩個筷子吃飯,都是需要對方的一根筷子才能吃)
以下代碼t1線程佔用o1,並且擷取到o2對象後才會釋放o1,而t2線程先佔用o2又去擷取o1,而此時的o1被t1線程佔用,o2被t2線程佔用,t1和t2都在無限等待,就會出現死結。
package javasimple;/** * 死結demo * @author haokui * */public class DieSynchronized { public static void main(String[] args) { /** * 建立並啟動兩個線程t1、t2。兩個線程都要共用o1、o2兩個對象 */ Object o1 = new Object(); Object o2 = new Object(); Thread t1 = new Thread(new T1(o1,o2)); Thread t2 = new Thread(new T2(o1,o2)); t1.start(); t2.start(); }}//建立兩個線程類class T1 implements Runnable { Object o1; Object o2; public T1(Object o1, Object o2){ this.o1 = o1; this.o2 = o2; } public void run() { //鎖o1和o2 synchronized (o1) { try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } synchronized (o2) { System.out.println("o2"); } } }}class T2 implements Runnable { Object o1; Object o2; public T2(Object o1, Object o2){ this.o1 = o1; this.o2 = o2; } public void run() { synchronized (o2) { try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } synchronized (o1) { System.out.println("o1"); } } }}
注意:只有o1和o2被共用的時候才會出現並發的情況,可通過建構函式的方式共用兩個對象。
以上就是本文的全部內容,希望對大家的學習有所協助,也希望大家多多支援幫客之家。