本文目錄一覽:
北大青鳥java培訓:如何避免死鎖?
什麼是死鎖,如何避免死鎖?線程A需要資源X,而線程B需要資源Y,而雙方都掌握有對方所要的資源,這種情況稱為死鎖(deadlock),或死亡擁抱(thedeadlyembrace)。
在並發程序設計中,江蘇電腦培訓建議死鎖(deadlock)是一種十分常見的邏輯錯誤。
通過採用正確的編程方式,死鎖的發生不難避免。
死鎖的四個必要條件在計算機專業的教材中,通常都會介紹死鎖的四個必要條件。
這四個條件缺一不可,或者說只要破壞了其中任何一個條件,死鎖就不可能發生。
我們來複習一下,這四個條件是:互斥(Mutualexclusion):存在這樣一種資源,它在某個時刻只能被分配給一個執行緒(也稱為線程)使用;持有(Holdandwait):當請求的資源已被佔用從而導致執行緒阻塞時,資源佔用者不但無需釋放該資源,而且還可以繼續請求更多資源;不可剝奪(Nopreemption):執行緒獲得到的互斥資源不可被強行剝奪,換句話說,只有資源佔用者自己才能釋放資源;環形等待(Circularwait):若干執行緒以不同的次序獲取互斥資源,從而形成環形等待的局面,想像在由多個執行緒組成的環形鏈中,每個執行緒都在等待下一個執行緒釋放它持有的資源。
解除死鎖的必要條件不難看出,在死鎖的四個必要條件中,第二、三和四項條件比較容易消除。
通過引入事務機制,往往可以消除第二、三兩項條件,方法是將所有上鎖操作均作為事務對待,一旦開始上鎖,即確保全部操作均可回退,同時通過鎖管理器檢測死鎖,並剝奪資源(回退事務)。
這種做法有時會造成較大開銷,而且也需要對上鎖模式進行較多改動。
消除第四項條件是比較容易且代價較低的辦法。
具體來說這種方法約定:上鎖的順序必須一致。
具體來說,我們人為地給鎖指定一種類似「水位」的方向性屬性。
無論已持有任何鎖,該執行緒所有的上鎖操作,必須按照一致的先後順序從低到高(或從高到低)進行,且在一個系統中,只允許使用一種先後次序。
請注意,放鎖的順序並不會導致死鎖。
也就是說,儘管按照鎖A,鎖B,放A,放B這樣的順序來進行鎖操作看上去有些怪異,但是只要大家都按先A後B的順序上鎖,便不會導致死鎖。
解決方法:1使用事務時,盡量縮短事務的邏輯處理過程,及早提交或回滾事務(細化處理邏輯,執行一段邏輯後便回滾或者提交,然後再執行其它邏輯,直到事物執行完畢提交);2設置死鎖超時參數為合理範圍,如:3分鐘-10分種;超過時間,自動放棄本次操作,避免進程懸掛; 3優化程序,檢查並避免死鎖現象出現; 4對所有的腳本和SP都要仔細測試,在正是版本之前。
5所有的SP都要有錯誤處理(通過@error) 6一般不要修改SQLSERVER事務的默認級別。
不推薦強行加鎖另外參考的解決方法:按同一順序訪問對象如果所有並發事務按同一順序訪問對象,則發生死鎖的可能性會降低。
例如,如果兩個並發事務獲得Supplier表上的鎖,然後獲得Part表上的鎖,則在其中一個事務完成之前,另一個事務被阻塞在Supplier表上。
第一個事務提交或回滾後,第二個事務繼續進行。
不發生死鎖。
將存儲過程用於所有的數據修改可以標準化訪問對象的順序。
怎麼處理JAVA多線程死鎖問題?
有兩種實現方法,分別是繼承Thread類與實現Runnable
接口
用synchronized關鍵字修飾同步方法
反對使用stop(),是因為它不安全。它會解除由線程獲取的所有鎖定,而且如果對象處於一種不連貫狀態,那麼
其他線程能在那種狀態下檢查和修改它們。結果很難檢查出真正的問題所在。suspend()方法容易發生死鎖。調用
suspend()的時候,目標線程會停下來,但卻仍然持有在這之前獲得的鎖定。此時,其他任何線程都不能訪問鎖定
的資源,除非被”掛起”的線程恢復運行。對任何線程來說,如果它們想恢複目標線程,同時又試圖使用任何一個
鎖定的資源,就會造成死鎖。所以不應該使用suspend(),而應在自己的Thread類中置入一個標誌,指出線程應該
活動還是掛起。若標誌指出線程應該掛起,便用wait()命其進入等待狀態。若標誌指出線程應當恢復,則用一個
notify()重新啟動線程。
程序員經常會遇到的死鎖情況有哪些?
第一,內存泄漏
C/C++程序還可能產生另一個指針問題:丟失對已分配內存的引用。當內存是在子程序中被分 配時,通常會出現這種問題,其結果是程序從子程序中返回時不會釋放內存。如此一來,對已分配的內存的引用就會丟失,只要操作系統還在運行中,則進程就會一 直使用該內存。這樣的結果是,曾佔用更多的內存的程序會降低系統性能,直到機器完全停止工作,才會完全清空內存。
第二,C指針錯誤
用C或C++編寫的程序,如Web服務器API模塊,有可能導致系統的崩潰,因為只要間接引 用指針(即,訪問指向的內存)中出現一個錯誤,就會導致操作系統終止所有程序。另外,使用了糟糕的C指針的Java模擬量(analog)將訪問一個空的 對象引用。Java中的空引用通常不會導致立刻退出JVM,但是前提是程序員能夠使用異常處理方法恰當地處理錯誤。在這方面,Java無需過多的關注,但 使用Java對可靠性進行額外的度量則會對性能產生一些負面影響。
第三,數據庫中的臨時表不夠用
許多數據庫的臨時表(cursor)數目都是固定的,臨時表即保留查詢結果的內存區域。在臨時表中的數據都被讀取後,臨時表便會被釋放,但大量同時進行的查詢可能耗盡數目固定的所有臨時表。這時,其他的查詢就需要列隊等候,直到有臨時表被釋放時才能再繼續運行。
第四,線程死鎖
由多線程帶來的性能改善是以可靠性為代價的,主要是因為這樣有可能產生線程死鎖。線程死鎖 時,第一個線程等待第二個線程釋放資源,而同時第二個線程又在等待第一個線程釋放資源。我們來想像這樣一種情形:在人行道上兩個人迎面相遇,為了給對方讓 道,兩人同時向一側邁出一步,雙方無法通過,又同時向另一側邁出一步,這樣還是無法通過。雙方都以同樣的邁步方式堵住了對方的去路。假設這種情況一直持續 下去,這樣就不難理解為何會發生死鎖現象了。
第五,磁盤已滿
導致系統無法正常運行的最可能的原因是磁盤已滿。一個好的網絡管理員會密切關注磁盤的使用情況,隔一定的時間,就需要將磁盤上的一些負載轉存到備份存儲介質中(例如磁帶)。
日誌文件會很快用光所有的磁盤空間。Web服務器的日誌文件、SQL*Net的日誌文件、 JDBC日誌文件,以及應用程序服務器日誌文件均與內存泄漏有同等的危害。可以採取措施將日誌文件保存在與操作系統不同的文件系統中。日誌文件系統空間已 滿時Web服務器也會被掛起,但機器自身被掛起的幾率已大大減低。
第六,服務器超載
Netscape Web服務器的每個連接都使用一個線程。Netscape Enterprise Web服務器會在線程用完後掛起,而不為已存在的連接提供任何服務。如果有一種負載分佈機制可以檢測到服務器沒有響應,則該服務器上的負載就可以分佈到其 它的Web服務器上,這可能會致使這些服務器一個接一個地用光所有的線程。這樣一來,整個服務器組都會被掛起。操作系統級別可能還在不斷地接收新的連接, 而應用程序(Web服務器)卻無法為這些連接提供服務。用戶可以在瀏覽器狀態行上看到connected(已連接)的提示消息,但這以後什麼也不會發生。
總之,還有許多因素也極有可能導致Web香港服務器租用或香港服務器託管站點無法工作。有許多種原因可能導致Web站點無法正常工作,這使得系統地檢查所有問題變得很困難。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/154667.html