自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

內(nèi)存飆升,罪魁禍?zhǔn)拙故撬梨i,這樣檢測(cè)和處理減少一半加班時(shí)間

開(kāi)發(fā) 前端
死鎖是進(jìn)程死鎖的簡(jiǎn)稱(chēng),是由Dijkstra于1965年研究銀行家算法時(shí)首先提出來(lái)的。它是計(jì)算機(jī)操作系統(tǒng)乃至并發(fā)程序設(shè)計(jì)中最難處理的問(wèn)題之一。實(shí)際上,死鎖問(wèn)題不僅在計(jì)算機(jī)系統(tǒng)中存在,在我們?nèi)粘I钪兴矎V泛存在。

你是否因?yàn)閷?xiě)出死鎖導(dǎo)致半夜加班,扣績(jī)效?你是否為小白程序員,還沒(méi)有接觸過(guò)并發(fā)編程不知道什么死鎖,你是否希望通過(guò)并發(fā)編程這塊突破自己的瓶頸,在新的一年挑戰(zhàn)高薪?那么Java并發(fā)編程中的死鎖是你避不開(kāi)的。

在通過(guò)Redis或者zookeeper實(shí)現(xiàn)分布式鎖時(shí)也可能出現(xiàn)死鎖,本篇文章從Java線程入手,解密以下幾點(diǎn):

什么是死鎖,死鎖如何產(chǎn)生

通過(guò)有趣的案例實(shí)現(xiàn)死鎖,并分析原因

分析死鎖產(chǎn)生的四個(gè)必要條件,并且解決死鎖

通過(guò)Java自帶工具檢測(cè)和定位死鎖位置

通過(guò)銀行家算法,規(guī)避死鎖問(wèn)題

什么是死鎖

死鎖是進(jìn)程死鎖的簡(jiǎn)稱(chēng),是由Dijkstra于1965年研究銀行家算法時(shí)首先提出來(lái)的。它是計(jì)算機(jī)操作系統(tǒng)乃至并發(fā)程序設(shè)計(jì)中最難處理的問(wèn)題之一。實(shí)際上,死鎖問(wèn)題不僅在計(jì)算機(jī)系統(tǒng)中存在,在我們?nèi)粘I钪兴矎V泛存在。

我們來(lái)看一個(gè)死鎖例子:

公司需要有工作經(jīng)驗(yàn)的員工,而剛畢業(yè)的小伙伴需要工作來(lái)獲得工作經(jīng)驗(yàn),這樣企業(yè)和應(yīng)屆生之間就產(chǎn)生了死鎖現(xiàn)象

這樣的例子還有很多,比如:兩輛車(chē)過(guò)橋

電影中的經(jīng)典情節(jié):我要的貨呢,你帶錢(qián)沒(méi)有,最后一手交錢(qián)一手交貨

所謂的死鎖其實(shí)是一種現(xiàn)象,就是兩個(gè)或兩個(gè)以上線程的多線程情況下,多個(gè)線程同時(shí)被阻塞,它們中的一個(gè)或全部都在等待某一鎖資源的釋放,由于線程被無(wú)期限的阻塞,因此程序不會(huì)繼續(xù)執(zhí)行,表現(xiàn)為卡住不動(dòng)。

如:線程1和線程2的運(yùn)行都需要A資源和B資源,此時(shí)線程1獲取了A資源,線程2獲取到了B鎖,此時(shí)線程1獲取不到B鎖和線程2獲取不到A鎖,導(dǎo)致兩個(gè)線程彼此僵持!

多把鎖場(chǎng)景

之前文章中的案例都是使用一把鎖,死鎖是線程需要多把鎖才會(huì)出現(xiàn),那么什么場(chǎng)景下需要多把鎖呢?

案例

家中住著張三和翠花夫妻二人,家庭條件一般,只有一個(gè)廚房,希望實(shí)現(xiàn)翠花做飯和張三洗菜互不相干

一把鎖解決

分析:

  • 定義一個(gè)廚房類(lèi),兩個(gè)功能,分別為洗菜和做飯【煮粥不是炒菜】
  • 定義一把鎖,直接將廚房鎖上
  • 假設(shè)洗菜需要1秒,做飯需要2秒
  • 洗菜和做飯時(shí)使用唯一的一把廚房鎖,將整個(gè)廚房鎖上,實(shí)現(xiàn)互不打擾

廚房類(lèi):

package com.tianzhen.thread;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class KitchenRoom {

// 鎖對(duì)象
public Object lock = new Object();

// 洗菜
public void washing() {
// 鎖住房間
synchronized (lock) {
// 輸出開(kāi)始時(shí)間 + 操作
System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss SSS")) + ":洗菜");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
// 做飯【煮粥】
public void cook() {
// 鎖上房間
synchronized (lock) {
// 輸出開(kāi)始時(shí)間 + 操作
System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss SSS")) + ":做飯");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}

運(yùn)行結(jié)果:

使用一把鎖的時(shí)候性能較低,因?yàn)殒i的范圍太大了,直接將廚房鎖住,只需將房間內(nèi)的每一個(gè)功能單獨(dú)鎖起來(lái)即可,比如:?jiǎn)为?dú)將洗菜,做飯,使用冰箱鎖住,不能多人同時(shí)使用,應(yīng)該將鎖細(xì)化,這樣同一個(gè)房間就可以同時(shí)做很多工作,廚房的利用率就會(huì)上來(lái),洗菜和做飯可以同步進(jìn)行,這樣是不就可以早點(diǎn)吃上美味了呢!

廚房改造:

package com.tianzhen.thread;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class KitchenRoom {

// 洗菜鎖
public Object washLock = new Object();

// 做飯鎖
public Object cookLock = new Object();

// 洗菜
public void washing() {
// 使用洗菜鎖
synchronized (washLock) {
System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss SSS")) + ":洗菜");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
// 做飯
public void cook() {
// 使用做飯鎖
synchronized (cookLock) {
System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss SSS")) + ":做飯");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}

運(yùn)行結(jié)果:

發(fā)現(xiàn)做飯【煮粥】和洗菜是同時(shí)開(kāi)始的,通過(guò)細(xì)化鎖,可以提升程序性能,必須要保障兩個(gè)操作沒(méi)有關(guān)聯(lián)性,比如煮粥不需要等菜洗好,如果是炒菜,就需要等待菜洗好才可以進(jìn)行。

鎖細(xì)粒度化的好處是:提高程序等性能,弊端在于:如果一個(gè)線程同時(shí)需要多把鎖,就可能產(chǎn)生死鎖

死鎖現(xiàn)象

以上邊的企業(yè)和面試者為例演示死鎖,企業(yè)招工需要有工作經(jīng)驗(yàn)的程序員,但是添甄剛畢業(yè),沒(méi)有工作經(jīng)驗(yàn),需要有工作才能獲取工作經(jīng)驗(yàn),這樣就導(dǎo)致企業(yè)招不到人,面試者找不到工作的尷尬境地!

分析

  • 這里有兩個(gè)條件,一個(gè)是工作經(jīng)驗(yàn),一個(gè)是工作
  • 企業(yè)先驗(yàn)證面試者是否有工作經(jīng)驗(yàn),才會(huì)給工作機(jī)會(huì)
  • 面試者需要先獲取工作,才能還有工作經(jīng)驗(yàn)
  • 兩者如果僵持不下,就會(huì)產(chǎn)生死鎖

代碼實(shí)現(xiàn)

package com.tianzhen.thread;

public class Deadhread {

// 工作鎖
private static Object work = new Object();
// 工作經(jīng)驗(yàn)鎖
private static Object workExperience = new Object();

public static void main(String[] args) {
// 企業(yè)線程
new Thread(() -> {
// 先鎖定工作經(jīng)驗(yàn)
synchronized (workExperience) {
System.out.println(Thread.currentThread().getName() + "我們需要有工作經(jīng)驗(yàn)的");
// 給工作機(jī)會(huì)
synchronized (work) {
System.out.println(Thread.currentThread().getName() + "恭喜你通過(guò)面試加入我們");
}
}
},"企業(yè)線程:").start();
// 員工線程
new Thread(() -> {
// 先獲取工作機(jī)會(huì)
synchronized (work) {
System.out.println(Thread.currentThread().getName() + "我需要工作才能有工作經(jīng)驗(yàn)");
// 有工作經(jīng)驗(yàn)
synchronized (workExperience) {
System.out.println(Thread.currentThread().getName() + "通過(guò)面試獲得了工作經(jīng)驗(yàn)");
}
}
},"面試者線程:").start();
}
}

運(yùn)行結(jié)果:發(fā)現(xiàn)程序再企業(yè)和面試者各輸出一句之后卡死不動(dòng)

原因

圖解

簡(jiǎn)單的說(shuō)就是:我需要的東西你占著,你需要的東西我占著,而且我們都不會(huì)腦筋急轉(zhuǎn)彎,就傻傻的等著對(duì)方讓步,拿到自己需要的東西之后繼續(xù)玩,但是大家都這么想那就誰(shuí)也別玩了。

死鎖產(chǎn)生的四個(gè)必要條件

  • 互斥使用:即當(dāng)資源被一個(gè)線程使用(占有)時(shí),別的線程不能使用
  • 不可搶占:資源請(qǐng)求者不能強(qiáng)制從資源占有者手中奪取資源,資源只能由資源占有者主動(dòng)釋放
  • 請(qǐng)求和保持:即當(dāng)資源請(qǐng)求者在請(qǐng)求其他的資源的同時(shí)保持對(duì)原有資源的占有
  • 循環(huán)等待:即存在一個(gè)等待隊(duì)列:企業(yè)線程占有workExperience鎖資源,面試者線程占有 work鎖 資源,面試者線程需要workExperience鎖資源,企業(yè)線程需要work鎖資源,彼此等待對(duì)方釋放資源。這樣就形成了一個(gè)等待環(huán)路

當(dāng)上述四個(gè)條件都成立的時(shí)候,便形成死鎖。當(dāng)然,死鎖的情況下如果打破上述任何一個(gè)條件,便可讓死鎖消失。

死鎖檢測(cè)

死鎖檢測(cè)其實(shí)非常簡(jiǎn)單,這里介紹兩種方式監(jiān)測(cè)死鎖,如果你有更好的辦法或工具記得在評(píng)論區(qū)分享哦!

方式1:命令檢測(cè)

  • 死鎖就會(huì)導(dǎo)致程序卡死不動(dòng),它的特點(diǎn)就是占用內(nèi)存比較多,首先找到占用內(nèi)存多的Java進(jìn)程
  • 其次通過(guò)jps命令找到對(duì)應(yīng)的java進(jìn)程號(hào)
  • 通過(guò)jstack 進(jìn)程號(hào)得到進(jìn)程信息
  • 通過(guò)進(jìn)程信息查看是否是死鎖,發(fā)生在什么地方

1、window下通過(guò)任務(wù)管理器查看進(jìn)程內(nèi)存占用情況,Linux下通過(guò) top 命令查看,這里以window為例

2、通過(guò)jps命令獲取該進(jìn)程的進(jìn)程號(hào)也就是PID

3、通過(guò) jstack PID 查看進(jìn)程信息

接下來(lái)的信息:在jstack輸出的信息中最后出現(xiàn)了死鎖提示,提示顯示在DeadThread.java文件的第39行和23行,那你去排查代碼就可以啦

方式2:通過(guò)jconsole工具

這個(gè)工具在查看JVM內(nèi)存時(shí)也是可以使用的,它是JDK中攜帶官方提供的工具,無(wú)需下載第三方插件即可使用

1、打開(kāi) jconsole 工具,在命令行輸入jconsole即可開(kāi)啟,箭頭右側(cè)就是該工具啟動(dòng)頁(yè)

2、選擇對(duì)應(yīng)的Java進(jìn)程查看信息,雙擊選中PID為128的Java進(jìn)程

3、選中線程,點(diǎn)擊下方檢查死鎖按鈕

4、死鎖檢測(cè)結(jié)果,也會(huì)將死鎖的信息展示出開(kāi)【右側(cè)信息需要雙擊左側(cè)線程名才會(huì)展示出來(lái)】

如何避免死鎖

這里說(shuō)的避免死鎖,其實(shí)是在生產(chǎn)環(huán)境中也就是項(xiàng)目上線運(yùn)行不要出現(xiàn)死鎖,不然又要被喊過(guò)去加班了,上邊說(shuō)了死鎖產(chǎn)生的四個(gè)條件,只要我們將這四個(gè)條件中的任意一個(gè)破壞就不會(huì)產(chǎn)生死鎖。

  • 禁止一個(gè)線程同時(shí)持有多把鎖
  • 具備相同的加鎖順序
  • 設(shè)置鎖超時(shí)
  • 死鎖檢測(cè)

方案1:具備相同加鎖順序

比如,企業(yè)和面試者的案例,調(diào)換兩者加鎖順序一致即可解決死鎖問(wèn)題

package com.tianzhen.thread;

public class DeadThread {

// 工作鎖
private static Object work = new Object();
// 工作經(jīng)驗(yàn)鎖
private static Object workExperience = new Object();

public static void main(String[] args) {
// 企業(yè)線程
new Thread(() -> {
// 工作
synchronized (work) {
System.out.println(Thread.currentThread().getName() + "來(lái)吧!加入我們,有無(wú)經(jīng)驗(yàn)都可");
// 工作經(jīng)驗(yàn)
synchronized (workExperience) {
System.out.println(Thread.currentThread().getName() + "感謝你的加入,為我們注入新鮮血液");
}
}
},"企業(yè)線程:").start();
// 員工線程
new Thread(() -> {
// 先獲取工作機(jī)會(huì)
synchronized (work) {
System.out.println(Thread.currentThread().getName() + "我沒(méi)有工作經(jīng)驗(yàn)");
// 有工作經(jīng)驗(yàn)
synchronized (workExperience) {
System.out.println(Thread.currentThread().getName() + "通過(guò)工作獲得了工作經(jīng)驗(yàn)");
}
}
},"面試者線程:").start();

}
}

運(yùn)行結(jié)果:

此時(shí)就不會(huì)出現(xiàn)死鎖,當(dāng)企業(yè)線程運(yùn)行占用work鎖,這是如果發(fā)生線程切換,面試者也是要獲取work鎖,此時(shí)發(fā)現(xiàn)獲取不到,就會(huì)進(jìn)入阻塞,CPU放棄執(zhí)行轉(zhuǎn)而執(zhí)行企業(yè)線程,此時(shí)企業(yè)線程獲取workExperience鎖,因?yàn)榧渔i順序相同,此鎖必然沒(méi)有被比別的線程占用可以獲得,繼續(xù)執(zhí)行,但是此時(shí)就無(wú)法實(shí)現(xiàn)交替執(zhí)行,如果需要交替執(zhí)行則需要使用線程通信實(shí)現(xiàn),后邊會(huì)安排此部分內(nèi)容

方案2:設(shè)置超時(shí)

因?yàn)?synchronized 不會(huì)自動(dòng)釋放,無(wú)法設(shè)置超時(shí)時(shí)間,此方案需要通過(guò)Lock接口實(shí)現(xiàn),改接口在Java并發(fā)編程合集的《Java線程安全問(wèn)題和解決方案》一文中有詳細(xì)介紹

  • 通過(guò)tryLock嘗試獲取鎖,如果獲取不到就立即失敗,不進(jìn)入阻塞,你也可以調(diào)用tryLock(long time, TimeUnit unit)方法,設(shè)置獲取所得超時(shí)時(shí)間,如果指定的時(shí)間沒(méi)有獲取到則繼續(xù)運(yùn)行
  • 在finally中記得通過(guò)unlock方法釋放鎖,如果不釋放鎖,就會(huì)一直持有,陷入死鎖
package com.tianzhen.thread;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class DeadThread {

// 工作鎖
private static Lock work = new ReentrantLock();
// 工作經(jīng)驗(yàn)鎖
private static Lock workExperience = new ReentrantLock();

public static void main(String[] args) {
// 企業(yè)線程
new Thread(() -> {
// 工作

if (workExperience.tryLock()) {
try {
System.out.println(Thread.currentThread().getName() + "沒(méi)有工作經(jīng)驗(yàn),立即失?。?);
// 工作鎖
if (work.tryLock()) {
try {
System.out.println(Thread.currentThread().getName() + "技術(shù)不行,立即失敗!");
} finally {
work.unlock();
}
}
System.out.println(Thread.currentThread().getName() + "有工作經(jīng)驗(yàn),通過(guò)面試,歡迎加入我們!");
} finally {
workExperience.unlock();
}
}
}, "企業(yè)線程:").start();
// 員工線程
new Thread(() -> {

if (work.tryLock()) {
try {
System.out.println(Thread.currentThread().getName() + "我需要工作,才能有工作經(jīng)驗(yàn)!");
// 工作鎖

if (workExperience.tryLock()) {
try {
System.out.println(Thread.currentThread().getName() + "沒(méi)有工作經(jīng)驗(yàn),告辭告辭!");
} finally {
workExperience.unlock();
}
}
System.out.println(Thread.currentThread().getName() + "有工作經(jīng)驗(yàn),獲取工作!");
} finally {
work.unlock();
}
}
}, "面試者線程:").start();

}
}

此方法一定要記得調(diào)用unlock釋放鎖,同樣可以解決死鎖問(wèn)題,因?yàn)椴粫?huì)像 synchronized 一樣無(wú)腦等待,而是非常機(jī)智,如果拿不到就不要了,就好比追一個(gè)女孩子,追了三年還不行就放棄吧,而synchronized就是永不言棄,等到天荒地老,非常癡情。傾我半世陽(yáng)光,許你天荒地老

你是不有更好的解決方案,趕緊掏出來(lái)嘮嘮吧!

銀行家算法中避免死鎖思維

銀行家算法是一種最有代表性的避免死鎖的算法。又被稱(chēng)為資源分配拒絕法。 在避免死鎖方法中允許進(jìn)程動(dòng)態(tài)地申請(qǐng)資源,但系統(tǒng)在進(jìn)行資源分配之前,應(yīng)先計(jì)算此次分配資源的安全性,若此次分配不會(huì)導(dǎo)致系統(tǒng)進(jìn)入不安全狀態(tài),則將資源分配給線程,否則進(jìn)程等待

銀行家算法中的數(shù)據(jù)結(jié)構(gòu)

1、可利用資源向量Available 是個(gè)含有m個(gè)元素的數(shù)組,其中的每一個(gè)元素代表一類(lèi)可利用的資源數(shù)目。如果Available[j]=K,則表示系統(tǒng)中現(xiàn)有Rj類(lèi)資源K個(gè)。

2、最大需求矩陣Max 這是一個(gè)n×m的矩陣,它定義了系統(tǒng)中n個(gè)進(jìn)程中的每一個(gè)進(jìn)程對(duì)m類(lèi)資源的最大需求。如果Max[i,j]=K,則表示進(jìn)程i需要Rj類(lèi)資源的最大數(shù)目為K。

3、分配矩陣Allocation 這也是一個(gè)n×m的矩陣,它定義了系統(tǒng)中每一類(lèi)資源當(dāng)前已分配給每一進(jìn)程的資源數(shù)。如果Allocation[i,j]=K,則表示進(jìn)程i當(dāng)前已分得Rj類(lèi)資源的數(shù)目為K。

4、需求矩陣Need 這也是一個(gè)n×m的矩陣,用以表示每一個(gè)進(jìn)程尚需的各類(lèi)資源數(shù)。如果Need[i,j]=K,則表示進(jìn)程i還需要Rj類(lèi)資源K個(gè),方能完成其任務(wù)。 Need[i,j]=Max[i,j]-Allocation[i,j]

操作系統(tǒng)的兩種狀態(tài)

安全序列:是指一個(gè)進(jìn)程序列{P1,…,Pn}是安全的,即對(duì)于每一個(gè)進(jìn)程Pi(1≤i≤n),它以后尚需要的資源量不超過(guò)系統(tǒng)當(dāng)前剩余資源量與所有進(jìn)程Pj (j < i )當(dāng)前占有資源量之和。

1、安全狀態(tài):如果存在一個(gè)由系統(tǒng)中所有進(jìn)程構(gòu)成的安全序列P1,…,Pn,則系統(tǒng)處于安全狀態(tài)。安全狀態(tài)一定是沒(méi)有死鎖發(fā)生。

2、不安全狀態(tài):不存在一個(gè)安全序列。不安全狀態(tài)不一定導(dǎo)致死鎖。

示例

首先判斷一下當(dāng)前的安全序列: 當(dāng)前狀態(tài),可利用資源向量有 1 6 2 2

1、P0: 已分配 0 0 3 2, 還需要 0 0 1 2,當(dāng)前可利用資源 1 6 2 2足夠分配給P0; Process Allocation Need Available(Available-Need) Available+Allocation P0 0 0 4 4 0 0 0 0 1 6 1 0 1 6 5 4 P0分配成功:進(jìn)入安全序列,分配完成后,將資源還給可利用資源

2、P1:已分配1 0 0 0, 還需要 1 7 5 0,當(dāng)前可利用資源 1 6 5 4不夠分配給P1; P1分配失敗

3、P2: 已分配1 3 5 4, 還需要 2 3 5 6,當(dāng)前可利用資源 1 6 5 4不夠分配給P2; P2分配失敗

4、P3: 已分配 0 3 3 2, 還需要 0 6 5 2,當(dāng)前可利用資源 1 6 5 4足夠分配給P3; Process Allocation Need Available(Available-Need) Available+Allocation P3 0 9 8 4 0 0 0 0 1 0 0 2 1 9 8 6 P3分配成功,進(jìn)入安全序列,分配完成后,將資源還給可利用資源

5、P4: 已分配 0 0 1 4, 還需要 0 6 5 6,當(dāng)前可利用資源 1 9 8 6足夠分配給P4; Process Allocation Need Available(Available-Need) Available+Allocation P4 0 6 6 10 0 0 0 0 1 3 3 0 1 9 9 10 P4分配成功,進(jìn)入安全序列,分配完成后,將資源還給可利用資源

6、P1: 已分配 1 0 0 0, 還需要 1 7 5 0,當(dāng)前可利用資源 1 9 9 10足夠分配給P1; Process Allocation Need Available(Available-Need) Available+Allocation P1 2 7 5 0 0 0 0 0 0 2 4 10 2 9 9 10 P1分配成功,進(jìn)入安全序列,分配完成后,將資源還給可利用資源

7、P2: 已分配 1 3 5 4, 還需要 2 3 5 6,當(dāng)前可利用資源 2 9 9 10足夠分配給P2; Process Allocation Need Available(Available-Need) Available+Allocation P2 3 6 10 10 0 0 0 0 0 6 4 4 3 12 14 14 P4分配成功,進(jìn)入安全序列,分配完成后,將資源還給可利用資源

所以:當(dāng)前的安全序列為: p0-p3-p4-p1-p2

如果在未分配的時(shí)候:p2請(qǐng)求 1 2 2 2 ,從資源池里給他分配,請(qǐng)問(wèn)可以分配嗎?

答: 如果滿足了P2的請(qǐng)求1 2 2 2 的話,要從可利用資源Available 1 6 2 2 中減去1 2 2 2,此時(shí)可利用資源為0 4 0 0 , 縱觀全局,如果滿足了P2的請(qǐng)求,那么別的進(jìn)程的需求都不能滿足,導(dǎo)致資源不夠分配,所以P2的請(qǐng)求不可以分配

Java代碼實(shí)現(xiàn)銀行家算法

import java.util.Scanner;

public class Banker {
int available[] = new int[]{3,3,2};//可利用的資源
int max[][] = new int[][]{{7,5,3},{3,2,2},{9,0,2},{2,2,2},{4,3,3}};//每個(gè)進(jìn)程最大資源數(shù)
int allocation[][] = new int[][]{{0,1,0},{2,0,0},{3,0,2},{2,1,1},{0,0,2}};//每個(gè)進(jìn)程目前擁有的資源數(shù)
int need[][] = new int[][]{{7,4,3},{1,2,2},{6,0,0},{0,1,1},{4,3,1}};//每個(gè)進(jìn)程需要的資源數(shù)
void showData() {
//展示數(shù)據(jù)輸出每個(gè)進(jìn)程的相關(guān)數(shù)
System.out.println("進(jìn)程號(hào) Max All Need ");
System.out.println(" A B C A B C A B C");
for(int i = 0;i<5;i++){
System.out.print(i+" ");
for(int m = 0;m<3;m++) System.out.print(max[i][m]+" ");
for(int m = 0;m<3;m++) System.out.print(allocation[i][m]+" ");
for(int m = 0;m<3;m++) System.out.print(need[i][m]+" ");
System.out.println();
}
}

boolean change(int inRequestNum,int inRequest[])//分配數(shù)據(jù)
{
int requestNum = inRequestNum;
int request[] = inRequest;
// for(int i=0;i<3;i++)System.out.println("修改前available"+available[i]);
if(!(request[0]<=need[requestNum][0]&&request[1]<=need[requestNum][1]&&request[2]<=need[requestNum][2]))
{
//request[0]<=need[requestNum][0]
//request[1]<=need[requestNum][1]
//request[2]<=need[requestNum][2]
//每一類(lèi)請(qǐng)求資源小于當(dāng)前線程need的資源數(shù)
System.out.println("請(qǐng)求的資源數(shù)超過(guò)了所需要的最大值,分配錯(cuò)誤");
return false;
}
if((request[0]<=available[0]&&request[1]<=available[1]&&request[2]<=available[2])==false)
{
//當(dāng)前線程的每一類(lèi)請(qǐng)求資源小于等于資源池對(duì)應(yīng)資源的數(shù)量
System.out.println("尚無(wú)足夠資源分配,必須等待");
return false;
}

for(int i = 0;i<3;i++)//試分配數(shù)據(jù)給請(qǐng)求的線程
{
available[i] = available[i]-request[i];
//資源池的每類(lèi)資源減去每類(lèi)請(qǐng)求資源數(shù)量
allocation[requestNum][i] = allocation[requestNum][i] + request[i];
//當(dāng)前線程allocation中每類(lèi)資源加上每類(lèi)資源請(qǐng)求數(shù)量
need[requestNum][i] = need[requestNum][i] - request[i];
//當(dāng)前線程need中每類(lèi)資源數(shù)量減去每類(lèi)資源的請(qǐng)求數(shù)量
}
// for(int i=0;i<3;i++)System.out.println("修改后available"+available[i]);
boolean flag = checkSafe(available[0],available[1],available[2]);//進(jìn)行安全性檢查并返回是否安全
// System.out.println("安全性檢查后"+flag);
if(flag==true)
{
System.out.println("能夠安全分配");
return true;
}
else//不能通過(guò)安全性檢查 恢復(fù)到未分配前的數(shù)據(jù)
{
System.out.println("不能夠安全分配");
for(int i = 0;i<3;i++)
{
available[i] = available[i]+request[i];
allocation[requestNum][i] = allocation[requestNum][i] - request[i];
need[requestNum][i] = need[requestNum][i] + request[i];
}
return false;
}
}
boolean checkSafe(int a,int b,int c)//安全性檢查
{
int work[] = new int[3];
work[0] = a;
work[1] = b;
work[2] = c;
int i=0;
boolean finish[] = new boolean[5];
while(i<5)//尋找一個(gè)能夠滿足的認(rèn)為完成后才去執(zhí)行下一進(jìn)程
{
if(finish[i]==false&&need[i][0]<=work[0]&&need[i][1]<=work[1]&&need[i][2]<=work[2])
{//找到滿足的修改work值,然后i=0,重新從開(kāi)始的為分配的中尋找
System.out.println("分配成功的是"+i);
for(int m = 0;m<3;m++)
work[m] =work[m] + allocation[i][m];
finish[i] = true;
i=0;
}
else//如果沒(méi)有找到直接i++
i++;
}
for(i=0;i<5;i++)//通過(guò)finish數(shù)組判斷是否都可以分配
{
if(finish[i]==false)
return false;
}
return true;
}
public static void main(String[] args)
{
Banker bank = new Banker();
bank.showData();
//請(qǐng)求線程資源存放的數(shù)組
int request[] =new int[3];
int requestNum;
String source[] = new String[]{"A","B","C"};
Scanner s = new Scanner(System.in);
String choice = new String();
while(true)//循環(huán)進(jìn)行分配
{
System.out.println("請(qǐng)輸入要請(qǐng)求的進(jìn)程號(hào)(0--4):");
requestNum = s.nextInt();
System.out.print("請(qǐng)輸入請(qǐng)求的資源數(shù)目");
for(int i = 0;i<3;i++)
{
System.out.println(source[i]+"資源的數(shù)目:");
request[i] = s.nextInt();
}
bank.change(requestNum, request);
System.out.println("是否再請(qǐng)求分配(y/n)");
choice = s.next();
if(choice.equals("n"))
break;
}
}
}

運(yùn)行結(jié)果:

總結(jié)

  • 掌握死鎖是什么,怎么產(chǎn)生
  • 可以寫(xiě)出死鎖代碼證明對(duì)死鎖的理解
  • 可以通過(guò)工具檢測(cè)死鎖和解決死鎖問(wèn)題
  • 掌握死鎖思維,在編程時(shí)避免死鎖

文章出自:??石添的編程哲學(xué)??,如有轉(zhuǎn)載本文請(qǐng)聯(lián)系【石添的編程哲學(xué)】今日頭條號(hào)。

責(zé)任編輯:武曉燕 來(lái)源: 今日頭條
相關(guān)推薦

2023-03-07 09:40:33

內(nèi)存死鎖操作系統(tǒng)

2019-05-27 10:22:26

Oracle日志數(shù)據(jù)庫(kù)

2019-06-04 14:19:53

AWS谷歌巖機(jī)

2015-11-23 10:29:48

app隱藏通信安卓耗電

2011-04-21 16:34:56

打印亂碼接口

2017-06-19 10:57:13

2021-12-12 21:51:54

人工智能銀行內(nèi)卷

2015-10-14 11:32:55

機(jī)房空調(diào)制冷

2011-08-12 10:04:52

數(shù)據(jù)中心宕機(jī)EPO

2018-01-29 23:13:47

大數(shù)據(jù)戰(zhàn)略數(shù)據(jù)分析

2022-11-16 16:14:46

單踏板模式特斯拉

2020-12-01 06:58:29

富領(lǐng)域模型服務(wù)

2009-02-25 08:58:30

裁員上網(wǎng)本微軟

2010-07-12 16:24:20

2020-10-26 16:35:53

內(nèi)存JavaThreadLocal

2024-01-29 12:42:37

AI訓(xùn)練

2020-10-19 06:49:18

內(nèi)存String

2009-06-03 08:48:26

2018-09-10 09:43:26

2025-03-05 05:00:00

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)