1. java中導(dǎo)致死鎖的原因 多個(gè)線程同時(shí)被阻塞,它們中的一個(gè)或者全部都在等待某個(gè)資源被釋放,而該資源又被其他線程鎖定,從而導(dǎo)致每一個(gè)線程都得等其它線程釋放其鎖定的資源,造成了所有線程都無(wú)法正常結(jié)束。這是從網(wǎng)上其他文檔看到的死鎖產(chǎn)生的四個(gè)必要條件:
當(dāng)上述四個(gè)條件都成立的時(shí)候,便形成死鎖。當(dāng)然,死鎖的情況下如果打破上述任何一個(gè)條件,便可讓死鎖消失。下面用java代碼來(lái)模擬一下死鎖的產(chǎn)生。 模擬兩個(gè)資源: public class ThreadResource { public static Object resource1 = new Object(); public static Object resource2 = new Object(); } 模擬線程1占用資源1并申請(qǐng)獲得資源2的鎖: public class Thread1 implements Runnable { @Override public void run() { try { System.out.println("Thread1 is running"); synchronized (ThreadResource.resource1) { System.out.println("Thread1 lock resource1"); Thread.sleep(2000);//休眠2s等待線程2鎖定資源2 synchronized (ThreadResource.resource2) { System.out.println("Thread1 lock resource2"); } System.out.println("Thread1 release resource2"); } System.out.println("Thread1 release resource1"); } catch (Exception e) { System.out.println(e.getMessage()); } System.out.println("Thread1 is stop"); } } 模擬線程2占用資源2并申請(qǐng)獲得資源1的鎖: public class Thread2 implements Runnable { @Override public void run() { try { System.out.println("Thread2 is running"); synchronized (ThreadResource.resource2) { System.out.println("Thread2 lock resource2"); Thread.sleep(2000);//休眠2s等待線程1鎖定資源1 synchronized (ThreadResource.resource1) { System.out.println("Thread2 lock resource1"); } System.out.println("Thread2 release resource1"); } System.out.println("Thread2 release resource2"); } catch (Exception e) { System.out.println(e.getMessage()); } System.out.println("Thread2 is stop"); } } 同時(shí)運(yùn)行倆個(gè)線程: public class ThreadTest { public static void main(String[] args) { new Thread(new Thread1()).start(); new Thread(new Thread2()).start(); } } 最后輸出結(jié)果是: Thread1 is running 并且程序一直無(wú)法結(jié)束。這就是由于線程1占用了資源1,此時(shí)線程2已經(jīng)占用資源2,。這個(gè)時(shí)候線程1想要使用資源2,線程2想要使用資源1,。兩個(gè)線程都無(wú)法讓步,導(dǎo)致程序死鎖。 2. java避免死鎖的解決意見(jiàn) 由上面的例子可以看出當(dāng)線程在同步某個(gè)對(duì)象里,再去鎖定另外一個(gè)對(duì)象的話,就和容易發(fā)生死鎖的情況。最好是線程每次只鎖定一個(gè)對(duì)象并且在鎖定該對(duì)象的過(guò)程中不再去鎖定其他的對(duì)象,這樣就不會(huì)導(dǎo)致死鎖了。比如將以上的線程改成下面這種寫(xiě)法就可以避免死鎖: public void run() { try { System.out.println("Thread1 is running"); synchronized (ThreadResource.resource1) { System.out.println("Thread1 lock resource1"); Thread.sleep(2000);//休眠2s等待線程2鎖定資源2 } System.out.println("Thread1 release resource1"); synchronized (ThreadResource.resource2) { System.out.println("Thread1 lock resource2"); } System.out.println("Thread1 release resource2"); } catch (Exception e) { System.out.println(e.getMessage()); } System.out.println("Thread1 is stop"); } 但是有的時(shí)候業(yè)務(wù)需要同時(shí)去鎖定兩個(gè)對(duì)象,比如轉(zhuǎn)賬業(yè)務(wù):A給B轉(zhuǎn)賬,需要同時(shí)鎖定A、B兩個(gè)賬戶(hù)。如果A、B相互同時(shí)轉(zhuǎn)賬的話就會(huì)出現(xiàn)死鎖的情況。這時(shí)可以定義一個(gè)規(guī)則:鎖定賬戶(hù)先后的規(guī)則。根據(jù)賬戶(hù)的某一個(gè)屬性(比如id或者h(yuǎn)asCode),判斷鎖定的先后。即每一次轉(zhuǎn)賬業(yè)務(wù)都是先鎖定A再鎖定B(或者先鎖定B在鎖定A),這樣也不會(huì)導(dǎo)致死鎖的發(fā)生。比如按照上面的例子,需要同時(shí)鎖定兩個(gè)資源,可以根據(jù)資源的hashcode值大小來(lái)判斷先后鎖定順序。可以這樣改造線程: public class Thread3 implements Runnable { @Override public void run() { try { System.out.println("Thread is running"); if ( ThreadResource.resource1.hashCode() > ThreadResource.resource2.hashCode() ) { //先鎖定resource1 synchronized (ThreadResource.resource1) { System.out.println("Thread lock resource1"); Thread.sleep(2000); synchronized (ThreadResource.resource2) { System.out.println("Thread lock resource2"); } System.out.println("Thread release resource2"); } System.out.println("Thread release resource1"); } else { //先鎖定resource2 synchronized (ThreadResource.resource2) { System.out.println("Thread lock resource2"); Thread.sleep(2000); synchronized (ThreadResource.resource1) { System.out.println("Thread lock resource1"); } System.out.println("Thread release resource1"); } System.out.println("Thread release resource2"); } } catch (Exception e) { System.out.println(e.getMessage()); } System.out.println("Thread1 is stop"); } } 總結(jié):死鎖常見(jiàn)于,線程在鎖定對(duì)象還沒(méi)釋放時(shí),又需要鎖定另一個(gè)對(duì)象,并且此時(shí)該對(duì)象可能被另一個(gè)線程鎖定。這種時(shí)候很容易導(dǎo)致死鎖。因此在開(kāi)發(fā)時(shí)需要慎重使用鎖,尤其是需要注意盡量不要在鎖里又加鎖。
注意:本文僅代表個(gè)人理解和看法喲!和本人所在公司和團(tuán)體無(wú)任何關(guān)系! |
|
來(lái)自: instl > 《Threading》