最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java并發(fā)編程之死鎖相關(guān)知識(shí)整理

 更新時(shí)間:2021年06月01日 16:07:58   作者:余飄飄  
前篇文章在講解線程安全的時(shí)候,有提到過為了保證每個(gè)線程都能正常執(zhí)行共享資源操作,Java引入了鎖機(jī)制,雖然這樣使多線程改善了系統(tǒng)的處理能力,然而也帶來了新的問題,其中之一:死鎖,需要的朋友可以參考下

一、什么是死鎖

所謂死鎖是指多個(gè)線程因競爭資源而造成的一種僵局(互相等待),若無外力作用,這些進(jìn)程都將無法向前推進(jìn)

在這里插入圖片描述

二、死鎖產(chǎn)生的條件

以下將介紹死鎖的必要條件,只要系統(tǒng)發(fā)生死鎖,這些條件必然成立,而只要上述條件之一不滿足,就不會(huì)發(fā)生死鎖

互斥條件

進(jìn)程要求對(duì)所分配的資源(如打印機(jī)〉進(jìn)行排他性控制,即在一段時(shí)間內(nèi)某資源僅為一個(gè)進(jìn)程所占有。此時(shí)若有其他進(jìn)程請求該資源,則請求進(jìn)程只能等待

不可剝奪條件

進(jìn)程所獲得的資源在未使用完畢之前,不能被其他進(jìn)程強(qiáng)行奪走,即只能由獲得該資源的進(jìn)程自己來釋放(只能是主動(dòng)釋放)

請求與保持條件

進(jìn)程已經(jīng)保持了至少一個(gè)資源,但又提出了新的資源請求,而該資源已被其他進(jìn)程占有,此時(shí)請求進(jìn)程被阻塞,但對(duì)自己已獲得的資源保持不放

循環(huán)等待條件

存在一種進(jìn)程資源的循環(huán)等待鏈,鏈中每一個(gè)進(jìn)程已獲得的資源同時(shí)被鏈中下一個(gè)進(jìn)程所請求s即存在一個(gè)處于等待狀態(tài)的進(jìn)程集合{PI, P2,…,, pn}

其中Pi等待的資源被P(i+1)占有( i=0,1,… , n-1),n等待的資源被Po占有

但也有可能Pi等待的資源被P(i+1)占有( i=0,1,… , n-1),但可以通過圈外也獲取資源(不死鎖),如圖所示

在這里插入圖片描述

三、死鎖產(chǎn)生的演示

接下來我們創(chuàng)建示例類,通過不同線程來獲取不同的鎖看看

public class Deadlock implements Runnable {

	private int flag;//用于區(qū)分走向
		
	//對(duì)象鎖 static 使不同線程引用的都是同一地址
	private static Object obj1 =new Object();
	
	//對(duì)象鎖 static 使不同線程引用的都是同一地址
	private static Object obj2 =new Object();
	
	public Deadlock(int flag) {
        this.flag = flag;
    }
	
	public void run(){
		
		if(flag == 1){
			synchronized (obj1){
				System.out.println(Thread.currentThread().getName ()
						+ "獲取Obj1,需要請求Obj2");
				try{
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				synchronized (obj2){
					System.out.println(Thread.currentThread().getName ()
						+ "已獲取Obj1、獲取Obj2");
				}
			}
		}else{
			synchronized (obj2){
				System.out.println(Thread.currentThread().getName ()
						+ "獲取Obj2,需要請求Obj1");
				try{
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				synchronized (obj1){
					System.out.println(Thread.currentThread().getName ()
						+ "已獲取Obj2、獲取Obj1");
				}
			}
		}
	}
}

這時(shí)我們創(chuàng)建兩個(gè)線程, 執(zhí)行這兩個(gè)obj的鎖,看看是否會(huì)產(chǎn)生死鎖

class DeadlockTest {
    public static void main(String[] args) {

        Thread thread1 = new Thread(new Deadlock(1),"線程1");
        Thread thread2 = new Thread(new Deadlock(2),"線程2");

        thread1.start();
        thread2.start();
    }
}
//運(yùn)行結(jié)果如下:
線程1獲取Obj1,需要請求Obj2
線程2獲取Obj2,需要請求Obj1

我們發(fā)現(xiàn)并沒有已獲取obj1、obj2或者以獲取obj2、獲取obj1 的輸出,因?yàn)樗麄儩M足了死鎖產(chǎn)生的條件

四、死鎖的預(yù)防

預(yù)防死鎖是設(shè)法至少破壞產(chǎn)生死鎖的四個(gè)必要條件之一嚴(yán)格的防止死鎖的出現(xiàn)

破壞互斥條件

“互斥”條件是無法破壞的。在死鎖預(yù)防里主要是破壞其他幾個(gè)必要條件,而不去涉及破壞“互斥”條件

破壞“占有并等待”條件

破壞“占有并等待”條件,就是在系統(tǒng)中不允許進(jìn)程在已獲得某種資源的情況下,申請其他資源

即要想出一個(gè)辦法,阻止進(jìn)程在持有資源的同時(shí)申請其他資源,有以下思路可提供:

  • 方法一:即創(chuàng)建進(jìn)程時(shí),要求它申請所需的全部資源,系統(tǒng)或滿足其所有要求,或什么也不給它
  • 方法二:要求每個(gè)進(jìn)程提出新的資源申請前,釋放它所占有的資源

這樣一個(gè)進(jìn)程在需要資源A時(shí),須先把它先前占有的資源R釋放掉,然后才能提出對(duì)A的申請,即使它可能很快又要用到資源R

破壞“不可搶占”條件

破壞“不可搶占”條件就是允許對(duì)資源實(shí)行搶奪

如果占有某些資源的一個(gè)進(jìn)程進(jìn)行下一步資源請求被拒絕,則該進(jìn)程必須釋放它最初占有的資源,如果有必要,可再次請求這些資源和另外的資源

如果一個(gè)進(jìn)程請求當(dāng)前被另一個(gè)進(jìn)程占有的一個(gè)資源,則操作系統(tǒng)可以搶占另一個(gè)進(jìn)程,要求它釋放資源。只有在任意兩個(gè)進(jìn)程的優(yōu)先級(jí)都不相同的條件下,方法二才能預(yù)防死鎖

破壞“循環(huán)等待”條件

破壞“循環(huán)等待”條件的一種方法,是將系統(tǒng)中的所有資源統(tǒng)一編號(hào),進(jìn)程可在任何時(shí)刻提出資源申請,但所有申請必須按照資源的編號(hào)順序(升序)提出。這樣做就能保證系統(tǒng)不出現(xiàn)死鎖。

五、死鎖的避免

死鎖的語法是是嚴(yán)格限制產(chǎn)生死鎖的條件,避免死鎖的方式不嚴(yán)格限制,因?yàn)榧词顾梨i的必要條件存在,也不一定發(fā)生死鎖。而是讓程序通過算法再滿足條件后避免死鎖

避免方法:有序資源分配算法

該算法實(shí)現(xiàn)步驟如下:

  • 必須為所有資源統(tǒng)一編號(hào),例如打印機(jī)為1、傳真機(jī)為2、磁盤為3等
  • 同類資源必須一次申請完,例如打印機(jī)和傳真機(jī)一般為同一個(gè)機(jī)器必須同時(shí)申請
  • 不同類資源必須按順序申請

舉例:有兩個(gè)進(jìn)程P1和P2,有兩個(gè)資源R1和R2,P1與P2線程、分別請求資源:R1、R2

P1先獲取R1、R2,而P2就請求等待P1釋放,這樣就破壞了環(huán)路條件,避免了死鎖的發(fā)生

避免方法:銀行家算法

銀行家算法(Banker's A1gorithm)是一個(gè)避免死鎖(Dead1ock)的著名算法,是由艾茲格·迪杰斯特拉在1965年為T.HE系統(tǒng)設(shè)計(jì)的一種避免死鎖產(chǎn)生的算法

它以銀行借貸系統(tǒng)的分配策略為基礎(chǔ),判斷并保證系統(tǒng)的安全運(yùn)行。流程圖如下:

在這里插入圖片描述

避免方法:順序加鎖

當(dāng)多個(gè)線程需要相同的一些鎖,但是按照不同的順序加鎖,死鎖就很容易發(fā)生

我們上面的示例代碼就是這樣的情況,線程1請求Obj1、Obj2,線程2請求Obj2、Obj1

而我們?nèi)绻軌虮WC所有的線程都是按照相同的順序獲得鎖,那么死鎖就不會(huì)發(fā)生

列如我們線程1請求Obj1、Obj2,線程2請求Obj1、Obj2

按照順序加鎖是一種有效的死鎖預(yù)防機(jī)制。但是這種方式需要事先知道所有可能會(huì)用到的鎖,但總有些時(shí)候是無法預(yù)知的,所以該種方式只適合特定場景

避免方法:限時(shí)加鎖

限時(shí)加鎖是線程在嘗試獲取鎖的時(shí)候加一個(gè)超時(shí)時(shí)間,若超過這個(gè)時(shí)間則放棄對(duì)該鎖請求,并回退并釋放所有已經(jīng)獲得的鎖,然后等待一段隨機(jī)的時(shí)間再重試

以下展示了兩個(gè)線程以不同的順序嘗試獲取相同的兩個(gè)鎖,在發(fā)生超時(shí)后回很并重試的場景:

//線程 1 鎖定A
Thread 1 locks A

//線程 2  鎖定B
Thread 2 locks B

//線程 1 嘗試去鎖定B,但已被鎖定
Thread 1 attempts to lock 8 but is blocked

//線程 2 嘗試去鎖定A,但已被鎖定
Thread 2 attempts to lock A but is blocked

//線程 1 等待鎖定B的時(shí)間超時(shí)了
Thread 1' s lock attempt on B times out

//線程 1 進(jìn)行回退并釋放鎖定A的資源
Thread 1 backs up and releases A as well

//線程 1 等待一段時(shí)間再重試獲取
Thread 1 waits randomly (e.g. 257 millis) before retrying
Thread 2's lock attempt on A times out
Thread 2 backs up and releases B as well
Thread 2 waits randomly (e.g.43 millis) before retrying

在上面的例子中,線程2比線程1早200毫秒進(jìn)行重試加鎖,因此它可以先成功地獲取到兩個(gè)鎖,這時(shí)線程1嘗試獲取鎖A并且處于等待狀態(tài),當(dāng)線程2結(jié)束時(shí),線程1也可以順利的獲得這兩個(gè)鎖

這種方式有兩個(gè)缺點(diǎn):

  • 當(dāng)線程數(shù)量少時(shí),該種方式可避免死鎖,但當(dāng)線程數(shù)量過多,這些線程的加鎖時(shí)限相同的概率就高很多,可能會(huì)導(dǎo)致超時(shí)后重試的死循環(huán)
  • Java中不能對(duì)synchronized同步塊設(shè)置超時(shí)時(shí)間,你需要?jiǎng)?chuàng)建自定義鎖或使用Java5中 java .util.concurrent包下的工具

到此這篇關(guān)于Java并發(fā)編程之死鎖相關(guān)知識(shí)整理的文章就介紹到這了,更多相關(guān)Java死鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • jdk8升級(jí)到j(luò)dk11如何升級(jí)的真實(shí)案例(親身經(jīng)歷)

    jdk8升級(jí)到j(luò)dk11如何升級(jí)的真實(shí)案例(親身經(jīng)歷)

    JDK11升級(jí)因G1GC性能提升及Spring?Boot?2.7+不再支持Java?8,需調(diào)整依賴和GC參數(shù),帶來內(nèi)存優(yōu)化和性能提升(如TPS增70%),并增強(qiáng)String、Files、Stream等API及新HTTP?Client
    2025-10-10
  • java實(shí)現(xiàn)字符串和日期類型相互轉(zhuǎn)換的方法

    java實(shí)現(xiàn)字符串和日期類型相互轉(zhuǎn)換的方法

    這篇文章主要介紹了java實(shí)現(xiàn)字符串和日期類型相互轉(zhuǎn)換的方法,涉及java針對(duì)日期與字符串的轉(zhuǎn)換與運(yùn)算相關(guān)操作技巧,需要的朋友可以參考下
    2017-02-02
  • 淺談spring-boot的單元測試中,@Before不被執(zhí)行的原因

    淺談spring-boot的單元測試中,@Before不被執(zhí)行的原因

    這篇文章主要介紹了淺談spring-boot的單元測試中,@Before不被執(zhí)行的原因,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-04-04
  • Java實(shí)現(xiàn)簡易HashMap功能詳解

    Java實(shí)現(xiàn)簡易HashMap功能詳解

    這篇文章主要介紹了Java實(shí)現(xiàn)簡易HashMap功能,結(jié)合實(shí)例形式詳細(xì)分析了Java實(shí)現(xiàn)HashMap功能相關(guān)原理、操作步驟與注意事項(xiàng),需要的朋友可以參考下
    2020-05-05
  • Java Socket+mysql實(shí)現(xiàn)簡易文件上傳器的代碼

    Java Socket+mysql實(shí)現(xiàn)簡易文件上傳器的代碼

    最近在做一個(gè)小項(xiàng)目,項(xiàng)目主要需求是實(shí)現(xiàn)一個(gè)文件上傳器,通過客戶端的登陸,把本地文件上傳到服務(wù)器的數(shù)據(jù)庫(本地的)。下面通過本文給大家分享下實(shí)現(xiàn)代碼,感興趣的朋友一起看看吧
    2016-10-10
  • 詳解SpringBoot Redis自適應(yīng)配置(Cluster Standalone Sentinel)

    詳解SpringBoot Redis自適應(yīng)配置(Cluster Standalone Sentinel)

    這篇文章主要介紹了詳解SpringBoot Redis自適應(yīng)配置(Cluster Standalone Sentinel),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • Spring Boot Admin Server管理客戶端過程詳解

    Spring Boot Admin Server管理客戶端過程詳解

    這篇文章主要介紹了Spring Boot Admin Server管理客戶端過程詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03
  • 輕松掌握java裝飾者模式

    輕松掌握java裝飾者模式

    這篇文章主要幫助大家輕松掌握java裝飾者模式,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-09-09
  • Java中JUC包(java.util.concurrent)下的常用子類

    Java中JUC包(java.util.concurrent)下的常用子類

    相信大家已經(jīng)對(duì)并發(fā)機(jī)制中出現(xiàn)的很多的常見知識(shí)點(diǎn)進(jìn)行了總結(jié),下面這篇文章主要給大家介紹了關(guān)于Java中JUC包(java.util.concurrent)下的常用子類的相關(guān)資料,文中通過圖文以及示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-12-12
  • nodejs連接dubbo服務(wù)的java工程實(shí)現(xiàn)示例

    nodejs連接dubbo服務(wù)的java工程實(shí)現(xiàn)示例

    這篇文章主要介紹了在項(xiàng)目遷移中,nodejs連接dubbo服務(wù)的java工程實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2022-03-03

最新評(píng)論

临澧县| 庄浪县| 岳普湖县| 甘谷县| 周宁县| 达拉特旗| 政和县| 天峻县| 鹿邑县| 大化| 卢湾区| 阜南县| 安康市| 九江县| 江安县| 万山特区| 连江县| 金坛市| 兴化市| 酉阳| 白玉县| 监利县| 临沧市| 滕州市| 永安市| 城步| 新郑市| 双桥区| 东港市| 长武县| 顺昌县| 凤冈县| 桐梓县| 隆化县| 太和县| 定安县| 金华市| 岫岩| 河源市| 文成县| 望城县|