『壹』 java怎麼避免死鎖
解決方式:
1、盡量使用tryLock(long timeout, TimeUnit unit)的方法(ReentrantLock、ReentrantReadWriteLock),設置超時時間,超時可以退出防止死鎖。
2、盡量使用java.util.concurrent(jdk 1.5以上)包的並發類代替手寫控制並發,比較常用的是ConcurrentHashMap、ConcurrentLinkedQueue、AtomicBoolean等等,實際應用中java.util.concurrent.atomic十分有用,簡單方便且效率比使用Lock更高 。
3、盡量降低鎖的使用粒度,盡量不要幾個功能用同一把鎖 。
4、盡量減少同步的代碼塊。
『貳』 什麼是java線程死鎖,如何解決死鎖問題
比如有兩個線程執行,線程t1,
線程t2
t1
需要獲取方法A的鎖標志,同時方法A調用了方法B,t1獲取了A的鎖標志,並獲取了B的鎖標志,才能完成執行
同時t2也在執行,t2獲取方法B的鎖標志,方法B調用了方法A,t2也需要獲取兩個方法A,B的鎖標志才能執行完成
當t1
獲取了A方法的鎖標志,同時t2獲取了B方法的鎖標志
那麼t1會等待t2釋放方法B的鎖標志,t2也在等待t1釋放方法A的鎖標志,這樣就形成了死鎖,都在等待....
『叄』 JAVA中如何去避免多線程產生的死鎖
Java線程死鎖需要如何解決,這個問題一直在我們不斷的使用中需要只有不斷的關鍵。不幸的是,使用上鎖會帶來其他問題。讓我們來看一些常見問題以及相應的解決方法: Java線程死鎖 Java線程死鎖是一個經典的多線程問題,因為不同的線程都在等待那些根本不可能被釋放的鎖,從而導致所有的工作都無法完成。假設有兩個線程,分別代表兩個飢餓的人,他們必須共享刀叉並輪流吃飯。他們都需要獲得兩個鎖:共享刀和共享叉的鎖。 假如線程 「A」獲得了刀,而線程「B」獲得了叉。線程「A」就會進入阻塞狀態來等待獲得叉,而線程「B」則阻塞來等待「A」所擁有的刀。這只是人為設計的例子,但盡管在運行時很難探測到,這類情況卻時常發生。雖然要探測或推敲各種情況是非常困難的,但只要按照下面幾條規則去設計系統,就能夠避免Java線程死鎖問題: 讓所有的線程按照同樣的順序獲得一組鎖。這種方法消除了 X 和 Y 的擁有者分別等待對方的資源的問題。 將多個鎖組成一組並放到同一個鎖下。前面Java線程死鎖的例子中,可以創建一個銀器對象的鎖。於是在獲得刀或叉之前都必須獲得這個銀器的鎖。 將那些不會阻塞的可獲得資源用變數標志出來。當某個線程獲得銀器對象的鎖時,就可以通過檢查變數來判斷是否整個銀器集合中的對象鎖都可獲得。如果是,它就可以獲得相關的鎖,否則,就要釋放掉銀器這個鎖並稍後再嘗試。 最重要的是,在編寫代碼前認真仔細地設計整個系統。多線程是困難的,在開始編程之前詳細設計系統能夠幫助你避免難以發現Java線程死鎖的問題。 Volatile 變數,volatile 關鍵字是 Java 語言為優化編譯器設計的。以下面的代碼為例: 1.class VolatileTest {
2.public void foo() {
3.boolean flag = false;
4.if(flag) {
5.//this could happen
6.}
7.}
8.} 一個優化的編譯器可能會判斷出if部分的語句永遠不會被執行,就根本不會編譯這部分的代碼。如果這個類被多線程訪問, flag被前面某個線程設置之後,在它被if語句測試之前,可以被其他線程重新設置。用volatile關鍵字來聲明變數,就可以告訴編譯器在編譯的時候,不需要通過預測變數值來優化這部分的代碼。 無法訪問的Java線程死鎖有時候雖然獲取對象鎖沒有問題,線程依然有可能進入阻塞狀態。在 Java 編程中IO就是這類問題最好的例子。當線程因為對象內的IO調用而阻塞時,此對象應當仍能被其他線程訪問。該對象通常有責任取消這個阻塞的IO操作。造成阻塞調用的線程常常會令同步任務失敗。如果該對象的其他方法也是同步的,當線程被阻塞時,此對象也就相當於被冷凍住了。 其他的線程由於不能獲得對象的Java線程死鎖,就不能給此對象發消息(例如,取消 IO 操作)。必須確保不在同步代碼中包含那些阻塞調用,或確認在一個用同步阻塞代碼的對象中存在非同步方法。盡管這種方法需要花費一些注意力來保證結果代碼安全運行,但它允許在擁有對象的線程發生阻塞後,該對象仍能夠響應其他線程。 編輯推薦: 1. Java多線程優化之偏向鎖原理分析 2. Java多線程實現非同步調用的方法 3. 使用Java多線程機制實現下載的方法介紹
『肆』 java多線程死鎖問題
public class Test520 {//測試類
public static void main(String[] args) {
Test1 t1=new Test1();//構造線程1
Test2 t2=new Test2();//構造線程2
t1.start();//啟動線程1
t2.start();//啟動線程2
}
}
class Test1 extends Thread{//線程類1
public void run() {//線程類1的run方法
synchronized (A.class) {//線程類1獲取A類的鎖
new A().a();//構建A類調用a方法,線程可以執行到這里
synchronized (B.class) {//線程1請求獲取B類的鎖,看後面的代碼我們知道B類的鎖在線程2中,形成死鎖
new B().b();//構造B類,調用b方法,這語句無法執行,因線程1始終無法獲得已被線程2獲得的B類鎖
}
}
}
}
class Test2 extends Thread{//線程類2
public void run() {//線程類2的run方法
synchronized (B.class) {//線程2獲取了B類的鎖,因此線程1無法在調用a方法後獲取B類鎖執行後面的語句
new A().a();//構造A類對象調用a方法,此語句可以執行
synchronized (A.class) {//線程2請求A類鎖,A類鎖此時被線程1持有
new B().b();//如果線程2能夠獲取A類鎖,就能執行這一步,測試知道,無法執行到這句
}
}
}
}
class A{//測試類
public void a() {
System.out.println("a");
}
}
class B{//測試類
public void b() {
System.out.println("b");
}
}
『伍』 求解java多線程的死鎖
你這是同步鎖,鎖的是A對象。有線程跟你一樣用 A對象當鎖的時候 ,只會有一條線程 來執行 B。其他線程都得等待。
1.A區域究竟什麼對象可以作為鎖?
對象,類對象。類對象 全局只有一個 比如 A.class ,當有人用到 這個類對象的時候 就會將其鎖住。不讓其他線程進入。
2.是不是我在一個線程中將A這個對象作為鎖,在另一個線程中對A這個對象進行操作,就會發生死鎖?
死鎖的根本原因1)是多個線程涉及到多個鎖,這些鎖存在著交叉,所以可能會導致了一個鎖依賴的閉環;2)默認的鎖申請操作是阻塞的。所以要避免死鎖,就要在一遇到多個對象鎖交叉的情況,就要仔細審查這幾個對象的類中的所有方法,是否存在著導致鎖依賴的環路的可能性。要採取各種方法來杜絕這種可能性。
你這樣 鎖不到的。舉個例子 死鎖 就是 x線程 鎖住了 A對象 然後 調用B對象的方法,y線程 鎖住了B對象調用A對象的方法,兩邊 都在互相嘗試獲取對方的鎖,但是拿不到。因為 x鎖住了A對象。y鎖住了B對象。他們互相拿不到 就叫死鎖。這只是個例子還有很多。
3不是說任何對象都可以作為一把鎖嗎?那麼每一個鎖我使用一個獨立的成員對象作為鎖,不就是可以很容易避開死鎖嗎?為什麼說死鎖很容易發生?
你每個鎖用一個獨立的成員對象作為鎖,沒問題,只要沒有存在交叉。上面那個例子一樣。
避免死鎖是一件困難的事,遵循以下原則有助於規避死鎖:
1、只在必要的最短時間內持有鎖,考慮使用同步語句塊代替整個同步方法;
2、盡量編寫不在同一時刻需要持有多個鎖的代碼,如果不可避免,則確保線程持有第二個鎖的時間盡量短暫;
3、創建和使用一個大鎖來代替若干小鎖,並把這個鎖用於互斥,而不是用作單個對象的對象級別鎖;
『陸』 JAVA程序設計,多線程且避免死鎖
JAVA中幾種常見死鎖及對策:解決死鎖沒有簡單的方法,這是因為線程產生死鎖都各有各的原因,而且往往具有很高的負載。大多數軟體測試產生不了足夠多的負載,所以不可能暴露所有的線程錯誤。在這里中,下面將討論開發過程常見的4類典型的死鎖和解決對策。(1)資料庫死鎖在資料庫中,如果一個連接佔用了另一個連接所需的資料庫鎖,則它可以阻塞另一個連接。如果兩個或兩個以上的連接相互阻塞,則它們都不能繼續執行,這種情況稱為資料庫死鎖。資料庫死鎖問題不易處理,通常數據行進行更新時,需要鎖定該數據行,執行更新,然後在提交或回滾封閉事務時釋放鎖。由於資料庫平台、配置的隔離級以及查詢提示的不同,獲取的鎖可能是細粒度或粗粒度的,它會阻塞(或不阻塞)其他對同一數據行、表或資料庫的查詢。基於資料庫模式,讀寫操作會要求遍歷或更新多個索引、驗證約束、執行觸發器等。每個要求都會引入鎖。此外,其他應用程序還可能正在訪問同一資料庫模式中的某些對象,並獲取不同應用程序所具有的鎖。所有這些因素綜合在一起,資料庫死鎖幾乎不可能被消除了。值得慶幸的是,資料庫死鎖通常是可恢復的:當資料庫發現死鎖時,它會強制銷毀一個連接(通常是使用最少的連接),並回滾其事務。這將釋放所有與已經結束的事務相關聯的鎖,至少允許其他連接中有一個可以獲取它們正在被阻塞的鎖。由於資料庫具有這種典型的死鎖處理行為,所以當出現資料庫死鎖問題時,資料庫常常只能重試整個事務。當資料庫連接被銷毀時,會拋出可被應用程序捕獲的異常,並標識為資料庫死鎖。如果允許死鎖異常傳播到初始化該事務的代碼層之外,則該代碼層可以啟動一個新事務並重做先前所有工作。當出現問題就重試,由於資料庫可以自由地獲取鎖,所以幾乎不可能保證兩個或兩個以上的線程不發生資料庫死鎖。此方法至少能保證在出現某些資料庫死鎖情況時,應用程序能正常運行。(2)資源池耗盡死鎖客戶端的增加導致資源池耗盡死鎖是由於負載而造成的,即資源池太小,而每個線程需要的資源超過了池中的可用資源。假設連接池最多有10個連接,同時有10個對外部並發調用。這些線程中每一個都需要一個資料庫連接用來清空池。現在,每個線程都執行嵌套的調用。則所有線程都不能繼續,但又都不放棄自己的第一個資料庫連接。這樣,10個線程都將被死鎖。研究此類死鎖,會發現線程存儲中有大量等待獲取資源的線程,以及同等數量的空閑且未阻塞的活動資料庫連接。當應用程序死鎖時,如果可以在運行時檢測連接池,就能確認連接池實際上已空。修復此類死鎖的方法包括:增加連接池的大小或者重構代碼,以便單個線程不需要同時使用很多資料庫連接。或者可以設置內部調用使用不同的連接池,即使外部調用的連接池為空,內部調用也能使用自己的連接池繼續。(3)單線程、多沖突資料庫連接死鎖對同一線程執行嵌套的調用有時出現死鎖,此情形即使在非高負載系統中通常也會發生。當第一個(外部)連接已獲取第二個(內部)連接所需要的資料庫鎖,則第二個連接將永久阻塞第一個連接,並等待第一個連接被提交或回滾,這就出現了死鎖情形。因為資料庫沒有注意到兩個連接之間的關系,所以資料庫不會將此情形檢測為死鎖。這樣即使不存在並發,此代碼也將導致死鎖。此情形有多種具體的變種,可以涉及多個線程和兩個以上的資料庫連接。(4)Java虛擬機鎖與資料庫鎖沖突這種情形發生在資料庫鎖與Java虛擬機鎖並存的時候。在這種情況下,一個線程佔有一個資料庫鎖並嘗試獲取Java虛擬機鎖。同時,另一個線程佔有Java虛擬機鎖並嘗試獲取資料庫鎖。此時,資料庫發現一個連接阻塞了另一個連接,但由於無法阻止連接繼續,所以不會檢測到死鎖。Java虛擬機發現同步的鎖中有一個線程,並有另一個嘗試進入的線程,所以即使Java虛擬機能檢測到死鎖並對它們進行處理,它還是不會檢測到這種情況。總而言之,JAVA應用程序中的死鎖是一個大問題——它能導致整個應用程序慢慢終止,還很難被分離和修復,尤其是當開發人員不熟悉如何分析死鎖環境的時候。五.死鎖的經驗法則筆者在開發中總結以下死鎖問題的經驗。(1)對大多數的Java程序員來說最簡單的防止死鎖的方法是對競爭的資源引入序號,如果一個線程需要幾個資源,那麼它必須先得到小序號的資源,再申請大序號的資源。可以在Java代碼中增加同步關鍵字的使用,這樣可以減少死鎖,但這樣做也會影響性能。如果負載過重,資料庫內部也有可能發生死鎖。(2)了解資料庫鎖的發生行為。假定任何資料庫訪問都有可能陷入資料庫死鎖狀況,但是都能正確進行重試。例如了解如何從應用伺服器獲取完整的線程轉儲以及從資料庫獲取資料庫連接列表(包括互相阻塞的連接),知道每個資料庫連接與哪個Java線程相關聯。了解Java線程和資料庫連接之間映射的最簡單方法是向連接池訪問模式添加日誌記錄功能。(3)當進行嵌套的調用時,了解哪些調用使用了與其它調用同樣的資料庫連接。即使嵌套調用運行在同一個全局事務中,它仍將使用不同的資料庫連接,而不會導致嵌套死鎖。(4)確保在峰值並發時有足夠大的資源池。(5)避免執行資料庫調用或在佔有Java虛擬機鎖時,執行其他與Java虛擬機無關的操作。最重要的是,多線程設計雖然是困難的,但在開始編程之前詳細設計系統能夠幫助你避免難以發現死鎖的問題。死鎖在語言層面上不能解決,就需要一個良好設計來避免死鎖。