java線程死鎖代碼 java線程中死鎖產(chǎn)生的原因

我的java多線程死鎖例子為什么沒(méi)寫(xiě)對(duì)?

死鎖的前提是。兩個(gè)人吃飯,都需要需要刀和叉但又只有一套, 其中一個(gè)人拿了叉,另一個(gè)拿了刀,就出現(xiàn)互相等待的情況。你的obj1和obj2就相當(dāng)于刀叉,但是你并沒(méi)有說(shuō)拿了叉,還會(huì)繼續(xù)去拿刀。你的代碼意思是,t1拿叉,然后放下叉,然后去拿刀。t2做的動(dòng)作是拿刀,放下刀,再拿叉。他們之間的動(dòng)作并不會(huì)導(dǎo)致矛盾。我給你改成下面這樣了,但是這樣也不一定會(huì)導(dǎo)致死鎖,因?yàn)槟銢](méi)有做循環(huán),只做一次操作,萬(wàn)一t1跑的快,瞬間就做完所有操作了,也不會(huì)阻塞t2.

成都創(chuàng)新互聯(lián)公司堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:網(wǎng)站制作、做網(wǎng)站、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時(shí)代的昌江網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!

if(Thread.currentThread().getName().equals("t1")){

synchronized(obj2){

System.out.println("線程1鎖定obj2");

synchronized(obj1){

System.out.println("線程1鎖定obj1");

}

}

}else if(Thread.currentThread().getName().equals("t2")){

synchronized(obj1){

System.out.println("線程2鎖定obj1");

synchronized(obj2){

System.out.println("線程2鎖定obj2");

}

}

}

JAVA死鎖

主線程保持著A對(duì)象的鎖意思就是主線程正在處理A對(duì)象,其他線程不能處理,要等待主線程結(jié)束之后其他線程才能處理A對(duì)象。

同理副線程正在處理B對(duì)象,A不能處理,所以主線程結(jié)束不了,一直在等待。

兩個(gè)線程都運(yùn)行不下去了就叫做死鎖,程序崩潰。

加鎖的意思就是某線程正在處理某對(duì)象,其他線程不能處理。

手打不容易,明白不明白都給分吧- -、

java synchronized 死鎖問(wèn)題

synchronized(obj){ ... } 稱(chēng)之為對(duì)obj加鎖的同步代碼塊。 你可以這么理解,每一個(gè)java對(duì)象,都具有一個(gè)鎖標(biāo)記。而這個(gè)鎖標(biāo)記,同時(shí)只能分配給一個(gè)線程。 有synchronized(o),意思是只有獲得o對(duì)象的鎖標(biāo)記之后,后面的代碼塊才會(huì)執(zhí)行,否則會(huì)等待。 回到你的例子。x1和x2是兩個(gè)不同的Xianc對(duì)象,但是,對(duì)于static的屬性來(lái)說(shuō),任何Xianc對(duì)象都共享相同的值。因此,實(shí)際上,x1的o1屬性和x2的o1屬性指向同一個(gè)對(duì)象,而x1的o2屬性和x2的o2屬性也指向相同的對(duì)象。 也就是說(shuō),Xianc.o1和Xianc.o2表示兩個(gè)對(duì)象,這兩個(gè)對(duì)象被x1和x2作為靜態(tài)屬性共享。 然后,我們開(kāi)始考慮鎖標(biāo)記的事情。程序中創(chuàng)建了兩個(gè)線程t1和t2,并首先啟動(dòng)了t1線程。t1線程與x1綁定,此時(shí)執(zhí)行的是flag == 0的代碼塊。 首先,遇到sync(o2),由于此時(shí)o2的鎖標(biāo)記還沒(méi)有被分配,因此t1線程就能獲得o2的鎖標(biāo)記,進(jìn)入代碼塊。 進(jìn)入代碼塊之后,接下來(lái)是sleep。由于t1線程sleep之后,釋放了cpu,導(dǎo)致t2線程開(kāi)始運(yùn)行。由于t2線程與x2綁定,此時(shí)執(zhí)行的是flag == 1的代碼塊。 這時(shí),t2線程遇到sync(o1)。由于o1的鎖標(biāo)記沒(méi)有被分配,因此t2線程就能獲得o1的鎖標(biāo)記,進(jìn)入代碼塊。同樣的,進(jìn)入代碼塊之后,t2也進(jìn)入了sleep狀態(tài),釋放了CPU。 過(guò)了一段時(shí)間,t1率先蘇醒,并被執(zhí)行。但是執(zhí)行過(guò)程中,會(huì)遇到syn(o1)。此時(shí),o1的鎖標(biāo)記被t2線程占據(jù),t1無(wú)法獲得鎖標(biāo)記,于是t1只能等待。 在等待過(guò)程中,t2也蘇醒了。但是t2遇到了syn(o2),而此時(shí)o2的鎖標(biāo)記被t1占據(jù),因此t2也只能等待。 于是,兩個(gè)線程相互等待,就形成了死鎖。 手打,樓主給分

java 死鎖

死鎖

死鎖是這樣一種情形:多個(gè)線程同時(shí)被阻塞,它們中的一個(gè)或者全部都在等待某個(gè)資源被釋放。由于線程被無(wú)限期地阻塞,因此程序不可能正常終止。

導(dǎo)致死鎖的根源在于不適當(dāng)?shù)剡\(yùn)用“synchronized”關(guān)鍵詞來(lái)管理線程對(duì)特定對(duì)象的訪問(wèn)?!皊ynchronized”關(guān)鍵詞的作用是,確保在某個(gè)時(shí)刻只有一個(gè)線程被允許執(zhí)行特定的代碼塊,因此,被允許執(zhí)行的線程首先必須擁有對(duì)變量或?qū)ο蟮呐潘缘脑L問(wèn)權(quán)。當(dāng)線程訪問(wèn)對(duì)象時(shí),線程會(huì)給對(duì)象加鎖,而這個(gè)鎖導(dǎo)致其它也想訪問(wèn)同一對(duì)象的線程被阻塞,直至第一個(gè)線程釋放它加在對(duì)象上的鎖。

由于這個(gè)原因,在使用“synchronized”關(guān)鍵詞時(shí),很容易出現(xiàn)兩個(gè)線程互相等待對(duì)方做出某個(gè)動(dòng)作的情形。代碼一是一個(gè)導(dǎo)致死鎖的簡(jiǎn)單例子。

//代碼一

class Deadlocker {

int field_1;

private Object lock_1 = new int[1];

int field_2;

private Object lock_2 = new int[1];

public void method1(int value) {

“synchronized” (lock_1) {

“synchronized” (lock_2) {

field_1 = 0; field_2 = 0;

}

}

}

public void method2(int value) {

“synchronized” (lock_2) {

“synchronized” (lock_1) {

field_1 = 0; field_2 = 0;

}

}

}

}

參考代碼一,考慮下面的過(guò)程:

◆ 一個(gè)線程(ThreadA)調(diào)用method1()。

◆ ThreadA在lock_1上同步,但允許被搶先執(zhí)行。

◆ 另一個(gè)線程(ThreadB)開(kāi)始執(zhí)行。

◆ ThreadB調(diào)用method2()。

◆ ThreadB獲得lock_2,繼續(xù)執(zhí)行,企圖獲得lock_1。但ThreadB不能獲得lock_1,因?yàn)門(mén)hreadA占有l(wèi)ock_1。

◆ 現(xiàn)在,ThreadB阻塞,因?yàn)樗诘却齌hreadA釋放lock_1。

◆ 現(xiàn)在輪到ThreadA繼續(xù)執(zhí)行。ThreadA試圖獲得lock_2,但不能成功,因?yàn)閘ock_2已經(jīng)被ThreadB占有了。

◆ ThreadA和ThreadB都被阻塞,程序死鎖。

當(dāng)然,大多數(shù)的死鎖不會(huì)這么顯而易見(jiàn),需要仔細(xì)分析代碼才能看出,對(duì)于規(guī)模較大的多線程程序來(lái)說(shuō)尤其如此。好的線程分析工具,例如JProbe Threadalyzer能夠分析死鎖并指出產(chǎn)生問(wèn)題的代碼位置。

隱性死鎖

隱性死鎖由于不規(guī)范的編程方式引起,但不一定每次測(cè)試運(yùn)行時(shí)都會(huì)出現(xiàn)程序死鎖的情形。由于這個(gè)原因,一些隱性死鎖可能要到應(yīng)用正式發(fā)布之后才會(huì)被發(fā)現(xiàn),因此它的危害性比普通死鎖更大。下面介紹兩種導(dǎo)致隱性死鎖的情況:加鎖次序和占有并等待。

加鎖次序

當(dāng)多個(gè)并發(fā)的線程分別試圖同時(shí)占有兩個(gè)鎖時(shí),會(huì)出現(xiàn)加鎖次序沖突的情形。如果一個(gè)線程占有了另一個(gè)線程必需的鎖,就有可能出現(xiàn)死鎖??紤]下面的情形,ThreadA和ThreadB兩個(gè)線程分別需要同時(shí)擁有l(wèi)ock_1、lock_2兩個(gè)鎖,加鎖過(guò)程可能如下:

◆ ThreadA獲得lock_1;

◆ ThreadA被搶占,VM調(diào)度程序轉(zhuǎn)到ThreadB;

◆ ThreadB獲得lock_2;

◆ ThreadB被搶占,VM調(diào)度程序轉(zhuǎn)到ThreadA;

◆ ThreadA試圖獲得lock_2,但lock_2被ThreadB占有,所以ThreadA阻塞;

◆ 調(diào)度程序轉(zhuǎn)到ThreadB;

◆ ThreadB試圖獲得lock_1,但lock_1被ThreadA占有,所以ThreadB阻塞;

◆ ThreadA和ThreadB死鎖。

必須指出的是,在代碼絲毫不做變動(dòng)的情況下,有些時(shí)候上述死鎖過(guò)程不會(huì)出現(xiàn),VM調(diào)度程序可能讓其中一個(gè)線程同時(shí)獲得lock_1和lock_2兩個(gè)鎖,即線程獲取兩個(gè)鎖的過(guò)程沒(méi)有被中斷。在這種情形下,常規(guī)的死鎖檢測(cè)很難確定錯(cuò)誤所在。

占有并等待

如果一個(gè)線程獲得了一個(gè)鎖之后還要等待來(lái)自另一個(gè)線程的通知,可能出現(xiàn)另一種隱性死鎖,考慮代碼二。

//代碼二

public class queue {

static java.lang.Object queueLock_;

Producer producer_;

Consumer consumer_;

public class Producer {

void produce() {

while (!done) {

“synchronized” (queueLock_) {

produceItemAndAddItToQueue();

“synchronized” (consumer_) {

consumer_.notify();

}

}

}

}

public class Consumer {

consume() {

while (!done) {

“synchronized” (queueLock_) {

“synchronized” (consumer_) {

consumer_.wait();

}

removeItemFromQueueAndProcessIt();

}

}

}

}

}

}

在代碼二中,Producer向隊(duì)列加入一項(xiàng)新的內(nèi)容后通知Consumer,以便它處理新的內(nèi)容。問(wèn)題在于,Consumer可能保持加在隊(duì)列上的鎖,阻止Producer訪問(wèn)隊(duì)列,甚至在Consumer等待Producer的通知時(shí)也會(huì)繼續(xù)保持鎖。這樣,由于Producer不能向隊(duì)列添加新的內(nèi)容,而Consumer卻在等待Producer加入新內(nèi)容的通知,結(jié)果就導(dǎo)致了死鎖。

在等待時(shí)占有的鎖是一種隱性的死鎖,這是因?yàn)槭虑榭赡馨凑毡容^理想的情況發(fā)展—Producer線程不需要被Consumer占據(jù)的鎖。盡管如此,除非有絕對(duì)可靠的理由肯定Producer線程永遠(yuǎn)不需要該鎖,否則這種編程方式仍是不安全的。有時(shí)“占有并等待”還可能引發(fā)一連串的線程等待,例如,線程A占有線程B需要的鎖并等待,而線程B又占有線程C需要的鎖并等待等。

要改正代碼二的錯(cuò)誤,只需修改Consumer類(lèi),把wait()移出“synchronized”()即可。

如何避免Java線程死鎖

Java線程死鎖需要如何解決,這個(gè)問(wèn)題一直在我們不斷的使用中需要只有不斷的關(guān)鍵。不幸的是,使用上鎖會(huì)帶來(lái)其他問(wèn)題。讓我們來(lái)看一些常見(jiàn)問(wèn)題以及相應(yīng)的解決方法: Java線程死鎖 Java線程死鎖是一個(gè)經(jīng)典的多線程問(wèn)題,因?yàn)椴煌木€程都在等待那些根本不可能被釋放的鎖,從而導(dǎo)致所有的工作都無(wú)法完成。假設(shè)有兩個(gè)線程,分別代表兩個(gè)饑餓的人,他們必須共享刀叉并輪流吃飯。他們都需要獲得兩個(gè)鎖:共享刀和共享叉的鎖。 假如線程 “A”獲得了刀,而線程“B”獲得了叉。線程“A”就會(huì)進(jìn)入阻塞狀態(tài)來(lái)等待獲得叉,而線程“B”則阻塞來(lái)等待“A”所擁有的刀。這只是人為設(shè)計(jì)的例子,但盡管在運(yùn)行時(shí)很難探測(cè)到,這類(lèi)情況卻時(shí)常發(fā)生。雖然要探測(cè)或推敲各種情況是非常困難的,但只要按照下面幾條規(guī)則去設(shè)計(jì)系統(tǒng),就能夠避免Java線程死鎖問(wèn)題: 讓所有的線程按照同樣的順序獲得一組鎖。這種方法消除了 X 和 Y 的擁有者分別等待對(duì)方的資源的問(wèn)題。 將多個(gè)鎖組成一組并放到同一個(gè)鎖下。前面Java線程死鎖的例子中,可以創(chuàng)建一個(gè)銀器對(duì)象的鎖。于是在獲得刀或叉之前都必須獲得這個(gè)銀器的鎖。 將那些不會(huì)阻塞的可獲得資源用變量標(biāo)志出來(lái)。當(dāng)某個(gè)線程獲得銀器對(duì)象的鎖時(shí),就可以通過(guò)檢查變量來(lái)判斷是否整個(gè)銀器集合中的對(duì)象鎖都可獲得。如果是,它就可以獲得相關(guān)的鎖,否則,就要釋放掉銀器這個(gè)鎖并稍后再嘗試。 最重要的是,在編寫(xiě)代碼前認(rèn)真仔細(xì)地設(shè)計(jì)整個(gè)系統(tǒng)。多線程是困難的,在開(kāi)始編程之前詳細(xì)設(shè)計(jì)系統(tǒng)能夠幫助你避免難以發(fā)現(xiàn)Java線程死鎖的問(wèn)題。 Volatile 變量,volatile 關(guān)鍵字是 Java 語(yǔ)言為優(yōu)化編譯器設(shè)計(jì)的。以下面的代碼為例: 1.class VolatileTest {

2.public void foo() {

3.boolean flag = false;

4.if(flag) {

5.//this could happen

6.}

7.}

8.} 一個(gè)優(yōu)化的編譯器可能會(huì)判斷出if部分的語(yǔ)句永遠(yuǎn)不會(huì)被執(zhí)行,就根本不會(huì)編譯這部分的代碼。如果這個(gè)類(lèi)被多線程訪問(wèn), flag被前面某個(gè)線程設(shè)置之后,在它被if語(yǔ)句測(cè)試之前,可以被其他線程重新設(shè)置。用volatile關(guān)鍵字來(lái)聲明變量,就可以告訴編譯器在編譯的時(shí)候,不需要通過(guò)預(yù)測(cè)變量值來(lái)優(yōu)化這部分的代碼。 無(wú)法訪問(wèn)的Java線程死鎖有時(shí)候雖然獲取對(duì)象鎖沒(méi)有問(wèn)題,線程依然有可能進(jìn)入阻塞狀態(tài)。在 Java 編程中IO就是這類(lèi)問(wèn)題最好的例子。當(dāng)線程因?yàn)閷?duì)象內(nèi)的IO調(diào)用而阻塞時(shí),此對(duì)象應(yīng)當(dāng)仍能被其他線程訪問(wèn)。該對(duì)象通常有責(zé)任取消這個(gè)阻塞的IO操作。造成阻塞調(diào)用的線程常常會(huì)令同步任務(wù)失敗。如果該對(duì)象的其他方法也是同步的,當(dāng)線程被阻塞時(shí),此對(duì)象也就相當(dāng)于被冷凍住了。 其他的線程由于不能獲得對(duì)象的Java線程死鎖,就不能給此對(duì)象發(fā)消息(例如,取消 IO 操作)。必須確保不在同步代碼中包含那些阻塞調(diào)用,或確認(rèn)在一個(gè)用同步阻塞代碼的對(duì)象中存在非同步方法。盡管這種方法需要花費(fèi)一些注意力來(lái)保證結(jié)果代碼安全運(yùn)行,但它允許在擁有對(duì)象的線程發(fā)生阻塞后,該對(duì)象仍能夠響應(yīng)其他線程。 編輯推薦: 1. Java多線程優(yōu)化之偏向鎖原理分析 2. Java多線程實(shí)現(xiàn)異步調(diào)用的方法 3. 使用Java多線程機(jī)制實(shí)現(xiàn)下載的方法介紹

Java Swing多線程死鎖問(wèn)題解析

在基于Java Swing進(jìn)行圖形界面開(kāi)發(fā)的時(shí)候 經(jīng)常遇到的就是Swing多線程問(wèn)題 我們可以想想一下 如果需要在一個(gè)圖形界面上顯示很多數(shù)據(jù) 這些數(shù)據(jù)是經(jīng)過(guò)長(zhǎng)時(shí)間 復(fù)雜的查詢和運(yùn)算得到的 如果在圖形界面的同一個(gè)線程中進(jìn)行查詢和運(yùn)算工作則會(huì)導(dǎo)致一段時(shí)間界面處于死機(jī)狀態(tài) 這會(huì)給用戶帶來(lái)不良的互動(dòng)感受 為了解決這個(gè)問(wèn)題 一般會(huì)單獨(dú)啟動(dòng)一個(gè)線程進(jìn)行運(yùn)算和查詢工作 并隨時(shí)更新圖形界面 這時(shí)候 另一個(gè)問(wèn)題就出現(xiàn)了 可能不僅沒(méi)有解決原來(lái)偶爾死機(jī)問(wèn)題 還可能導(dǎo)致程序徹底死掉 幸運(yùn)的是在JDK中暗藏了一個(gè)中斷程序的快捷鍵 就是CTRL+BREAK 這個(gè)快捷鍵Sun并沒(méi)有在文檔中公布 如果在命令行模式下啟動(dòng)Java程序 然后按CTRL+BREAK鍵 會(huì)得到堆棧的跟蹤信息 從這些跟蹤信息中就可以知道具體引發(fā)死機(jī)的位置了

當(dāng)一個(gè)程序產(chǎn)生死鎖的時(shí)候 你一定會(huì)希望盡快找到原因并且解決它 這時(shí)候 你一般的精力會(huì)用在查找引發(fā)死鎖的位置 另一半的精力會(huì)用于對(duì)堆棧進(jìn)行跟蹤一確定引發(fā)死鎖的原因 但是在Java Swing程序中 你的所有努力可能都是沒(méi)有價(jià)值的 這是因?yàn)镴ava對(duì)Swing的多線程編程有一個(gè)特殊要求 就是在Swing里 只能在與Swing相同的線程里對(duì)GUI元件進(jìn)行修改

也就是說(shuō) 如果你要執(zhí)行類(lèi)似于jLabel setText( blabla )代碼 必須在Swing線程中 而不允許在其他線程當(dāng)中 如果必須在其他線程中修改元件 可以使用類(lèi)似一下方式解決

SwingUtilities invokeLater(new Runnable() {

public void run() {

jLabel setText( blabla );

}

}

invokeLater方法雖然表面有時(shí)間延遲執(zhí)行含義 但是實(shí)際上幾乎沒(méi)有任何影響 可能在幾毫秒之內(nèi)就會(huì)被執(zhí)行 另外還有一個(gè)invokeAndWait方法 除非特殊需要 否則幾乎是不用的

在不使用invokeLater的情況下 導(dǎo)致刷新問(wèn)題是可以理解的 但是導(dǎo)致死鎖就優(yōu)點(diǎn)令人匪夷所思了 幸運(yùn)的是 不是任何時(shí)候都需要調(diào)用改方法 這是因?yàn)榇蠖鄶?shù)情況下 我們都是在與Swing同一個(gè)線程里進(jìn)行界面更新 例如監(jiān)聽(tīng)按鈕點(diǎn)擊事件的ActionListener actionPerformed方法就是運(yùn)行在與Swing相同的線程中的 但是如果在回調(diào)類(lèi)中引用了另一個(gè)類(lèi) 并且是不屬于AWT/Swing的 那么結(jié)果就很難確定了 所以說(shuō)使用invokeLater應(yīng)該是最安全的

需要注意的是 在invokeLater做的任何事情 都會(huì)導(dǎo)致Swing線程窗口繪制工作暫停下來(lái) 等候invokeLater工作結(jié)束 所以不要在invokeLater進(jìn)行耗時(shí)操作 盡量只執(zhí)行那些界面繪制相關(guān)的工作 可以通過(guò)代碼重構(gòu) 將那些與界面更新相關(guān)的代碼集中起來(lái)統(tǒng)一處理

lishixinzhi/Article/program/Java/gj/201311/27498

新聞名稱(chēng):java線程死鎖代碼 java線程中死鎖產(chǎn)生的原因
本文URL:http://muchs.cn/article36/hjdjpg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供ChatGPT、面包屑導(dǎo)航、微信小程序網(wǎng)站導(dǎo)航、電子商務(wù)、網(wǎng)站策劃

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

h5響應(yīng)式網(wǎng)站建設(shè)