哲学家就餐与死锁问题,死锁产生的条件以及解决方案
請結合經典案例-哲學家就餐,來談談你對死鎖的理解,以及怎么預防和解除死鎖?
哲學家就餐
描述:在一張圓桌上,有n個哲學家,n支筷子,他們的生活方式只是交替地進行思考和進餐,饑餓時便試圖取其左、右最靠近他的筷子,只有在他拿到兩支筷子時才能進餐,進餐完畢,放下筷子又繼續(xù)思考。
根據描述,實現代碼如下:
import java.util.Random; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit;public class Question17 {public static void main(String[] args) {ExecutorService exec = Executors.newCachedThreadPool();int sum = 5;Chopstick[] chopsticks = new Chopstick[sum];for (int i = 0; i < sum; i++) {chopsticks[i] = new Chopstick(i);}for (int j = 0; j < sum; j++) {exec.execute(new Philosopher(chopsticks[j], chopsticks[(j + 1) % sum], j));}} }// 筷子 class Chopstick {// 筷子位置??private int id;// 狀態(tài)private boolean isUsed = false;public Chopstick(int id) {this.id = id;}// 拿取public synchronized void take() throws InterruptedException {while (isUsed) {wait();}System.err.println(this + " 被使用");isUsed = true;}// 放下public synchronized void drop() {isUsed = false;System.err.println(this + " 被放下");notifyAll();}@Overridepublic String toString() {return "筷子[" + id + "]";} }// 哲學家 class Philosopher implements Runnable {private Chopstick left;private Chopstick right;private int id;private Random rand = new Random();public Philosopher(Chopstick left, Chopstick right, int id) {this.left = left;this.right = right;this.id = id;}@Overridepublic void run() {while (!Thread.interrupted()) {try {think();System.out.println(this + " 想吃飯!");eat();} catch (InterruptedException e) {System.err.println(this + " InterruptedException");}}}// 思考private void think() throws InterruptedException {System.out.println(this + " 思考...");TimeUnit.MILLISECONDS.sleep(rand.nextInt(1) * 100);}// 吃飯private void eat() throws InterruptedException {left.take();right.take();System.out.println(this + " 正在吃飯...");TimeUnit.MILLISECONDS.sleep(rand.nextInt(2) * 100);left.drop();right.drop();}@Overridepublic String toString() {return "哲學家[" + id + "]";} }
通過運行結果,我們可以發(fā)現,到最后,沒有一個哲學家能過同時獲取兩只筷子吃飯。
二、為什么會產生死鎖
死鎖問題被認為是線程/進程間切換消耗系統(tǒng)性能的一種極端情況。在死鎖時,線程/進程間相互等待資源,而又不釋放自身的資源,導致無窮無盡的等待,其結果是任務永遠無法執(zhí)行完成。哲學家問題便是線程資源競爭導致的死鎖現象,在程序運行一段時間后,程序所處的狀態(tài)是n位哲學家(n個線程)都各自獲取了一只筷子的狀態(tài),此時所有哲學家都想獲取第二只筷子去吃飯,但是共享資源n只筷子已經都被n位哲學家握在手里了,彼此想要的筷子都在其他哲學家手中,又沒有機制能讓任何哲學家放棄握在手中的筷子,從而照成了所有哲學家(所有線程)都在等待其他人手中資源的死鎖問題。
產生死鎖的四個必要條件:?
?
三、死鎖的解除與預防
一般解決死鎖的途徑分為死鎖的預防,避免,檢測與恢復這三種。
死鎖的預防是要求線程/進程申請資源時遵循某種協(xié)議,從而打破產生死鎖的四個必要條件中的一個或幾個,保證系統(tǒng)不會進入死鎖狀態(tài)。
死鎖的避免不限制線程/進程有關申請資源的命令,而是對線程/進程所發(fā)出的每一個申請資源命令加以動態(tài)地檢查,并根據檢查結果決定是否進行資源分配。
死鎖檢測與恢復是指系統(tǒng)設有專門的機構,當死鎖發(fā)生時,該機構能夠檢測到死鎖發(fā)生的位置和原因,并能通過外力破壞死鎖發(fā)生的必要條件,從而使得并發(fā)進程從死鎖狀態(tài)中恢復出來。
對于java程序來說,產生死鎖時,我們可以用jvisualvm/jstack來分析程序產生的死鎖原因,根治死鎖問題。
總結
以上是生活随笔為你收集整理的哲学家就餐与死锁问题,死锁产生的条件以及解决方案的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 以Java的视角来聊聊BIO、NIO与A
- 下一篇: 过滤器跟拦截器的区别