哲學家就餐問題(java全代碼)

題目

有N個哲學家圍坐在一張圓桌旁,桌上只有N把叉子,每對哲學家中間各有一把。

哲學家的兩種行為:

一、思考

二、吃意大利面

哲學家只能拿起手邊左邊或右邊的叉子

吃飯需要兩把叉子

正確地模仿哲學家的行為

方法一

一次只允許四個人搶叉子
import java.util.concurrent.Semaphore;
class 方法一 {public static class PhilosopherTest {//一次只允許四個人搶叉子static final Semaphore count = new Semaphore(4);//五只叉子static final Semaphore[] mutex = {new Semaphore(1),new Semaphore(1),new Semaphore(1),new Semaphore(1),new Semaphore(1)};static class Philosopher extends Thread {Philosopher(int name) {super.setName(String.valueOf(name));}@Overridepublic void run() {do {try {//只有四個人有搶叉子的資格count.acquire();Integer i = Integer.parseInt(super.getName());//規定都先拿左手邊的叉子,于是四個人左手都有叉子mutex[i].acquire();//大家開始搶右邊的叉子mutex[(i + 1) % 5].acquire();//誰先搶到誰第一個開吃System.out.println("哲學家" + i + "號吃飯!");//吃完放下左手的叉子,對于左邊人來說,就是他的右叉子,直接開吃mutex[i].release();//再放下右手的叉子mutex[(i + 1) % 5].release();//吃完了,開始思考,由于放下了右手的叉子,相當于給一個叉子沒有的哲學家一個左叉子count.release();//模擬延遲Thread.sleep(2000);} catch (InterruptedException e) {System.out.println("異常");}} while (true);}}public static void main(String[] args) {Philosopher[] threads=new Philosopher[5];for (int i = 0; i < 5; i++) {threads[i] = new Philosopher(i);}for (Philosopher i : threads) {i.start();}}}
}

count每次acquire就會減一,使得第五個來訪問的哲學家被阻塞

下面是將think和eat方法分離出來的改進版本:

import java.util.concurrent.Semaphore;
public class 方法一改進 {public static class PhilosopherTest {// 一次只允許四個人搶叉子static final Semaphore count = new Semaphore(4);// 五只叉子static final Semaphore[] mutex = {new Semaphore(1),new Semaphore(1),new Semaphore(1),new Semaphore(1),new Semaphore(1)};static class Philosopher extends Thread {Philosopher(int name) {super.setName(String.valueOf(name));}@Overridepublic void run() {do {try {think();eat();} catch (InterruptedException e) {System.out.println("異常");}} while (true);}public void think() throws InterruptedException {// 模擬思考System.out.println("哲學家" + super.getName() + "號正在思考");Thread.sleep(2000); // 模擬延遲}public void eat() throws InterruptedException {// 只有四個人有搶叉子的資格count.acquire();Integer i = Integer.parseInt(super.getName());// 規定都先拿左手邊的叉子,于是四個人左手都有叉子mutex[i].acquire();// 大家開始搶右邊的叉子mutex[(i + 1) % 5].acquire();// 誰先搶到誰第一個開吃System.out.println("哲學家" + i + "號吃飯!");// 吃完放下左手的叉子,對于左邊人來說,就是他的右叉子,直接開吃mutex[i].release();// 再放下右手的叉子mutex[(i + 1) % 5].release();// 吃完了,開始思考,由于放下了右手的叉子,相當于給一個叉子沒有的哲學家一個左叉子count.release();}}public static void main(String[] args) {PhilosopherTest.Philosopher[] threads=new PhilosopherTest.Philosopher[5];for (int i = 0; i < 5; i++) {threads[i] = new PhilosopherTest.Philosopher(i);}for (PhilosopherTest.Philosopher i : threads) {i.start();}}}}

本質沒區別。

方法二

先獲取左筷子,一段時間內申請不到右筷子就將左筷子釋放
import java.util.concurrent.Semaphore;public class 方法二 {//先獲取左筷子,一段時間內申請不到右筷子就將左筷子釋放// Five forksstatic final Semaphore[] mutex = {new Semaphore(1),new Semaphore(1),new Semaphore(1),new Semaphore(1),new Semaphore(1)};static class Philosopher extends Thread {Philosopher(int name) {super.setName(String.valueOf(name));}@Overridepublic void run() {do {try {Integer i = Integer.parseInt(super.getName());//嘗試獲取左筷子if (mutex[i].tryAcquire()) {//嘗試獲取右筷子if (mutex[(i + 1) % 5].tryAcquire()) {System.out.println("哲學家" + i + "號吃飯!");mutex[i].release();mutex[(i + 1) % 5].release();Thread.sleep(2000);} else {//如果獲取不到右筷子,就把左筷子扔了mutex[i].release();}}//這里沒有else,獲取不到左筷子就一直嘗試} catch (InterruptedException e) {System.out.println("異常");}} while (true);}}public static void main(String[] args) {Philosopher[] threads=new Philosopher[5];for (int i = 0; i < 5; i++) {threads[i] = new Philosopher(i);}for (Philosopher i : threads) {i.start();}}
}

下面是將eat和think分出來的版本:

import java.util.concurrent.Semaphore;
class 方法二改進 {//先獲取左筷子,一段時間內申請不到右筷子就將左筷子釋放public static class Philosopher extends Thread {private static Semaphore[] chopsticks = {new Semaphore(1), new Semaphore(1), new Semaphore(1), new Semaphore(1), new Semaphore(1)};private int id;public Philosopher(int id) {this.id = id;}@Overridepublic void run() {while (true) {think();eat();}}public void think() {System.out.println("哲學家_" + this.id + "正在思考");//思考一秒時間try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}public void eat() {try {if (chopsticks[this.id].tryAcquire()) { // 獲取左筷子if (chopsticks[(this.id + 1) % chopsticks.length].tryAcquire()) { // 獲取右筷子System.out.println("哲學家_" + this.id + "正在吃飯");// 吃飯花一秒時間try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();} finally {chopsticks[this.id].release(); // 放下左筷子chopsticks[(this.id + 1) % chopsticks.length].release(); // 放下右筷子}} else {chopsticks[this.id].release(); // 如果不能獲取右筷子,釋放左筷子}}} catch (Exception e) {e.printStackTrace();}}public static void main(String[] args) {Philosopher[] threads=new Philosopher[5];for (int i = 0; i < 5; i++) {threads[i] = new Philosopher(i);}for (Philosopher i : threads) {i.start();}}}}

下面是用可重入鎖實現的版本:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;class Philosopher extends Thread {private Lock leftFork;private Lock rightFork;private int philosopherId;private int eatCount; // 計數器public Philosopher(int philosopherId, Lock leftFork, Lock rightFork) {this.philosopherId = philosopherId;this.leftFork = leftFork;this.rightFork = rightFork;this.eatCount = 0;}private void think() throws InterruptedException {System.out.println("Philosopher " + philosopherId + " is thinking.");Thread.sleep((long) (Math.random() * 1000));}private void eat() throws InterruptedException {System.out.println("Philosopher " + philosopherId + " is eating.");Thread.sleep((long) (Math.random() * 1000));eatCount++;}@Overridepublic void run() {try {while (eatCount < 1) { // 表示每個哲學家吃了1次think();/* 使用ReentrantLock鎖, 該類中有一個tryLock()方法, 在指定時間內獲取不到鎖對象, 就從阻塞隊列移除,不用一直等待。當獲取了左手邊的筷子之后, 嘗試獲取右手邊的筷子, 如果該筷子被其他哲學家占用, 獲取失敗, 此時就先把自己左手邊的筷子,給釋放掉. 這樣就避免了死鎖問題 */if (leftFork.tryLock()) {System.out.println("Philosopher " + philosopherId + " picked up left fork.");if (rightFork.tryLock()) {System.out.println("Philosopher " + philosopherId + " picked up right fork.");eat();rightFork.unlock();System.out.println("Philosopher " + philosopherId + " put down right fork.");}leftFork.unlock();System.out.println("Philosopher " + philosopherId + " put down left fork.");}}} catch (InterruptedException e) {e.printStackTrace();}}
}class DiningPhilosophers {public static void main(String[] args) {int numPhilosophers = 5;Philosopher[] philosophers = new Philosopher[numPhilosophers];Lock[] forks = new ReentrantLock[numPhilosophers];for (int i = 0; i < numPhilosophers; i++) {forks[i] = new ReentrantLock();}for (int i = 0; i < numPhilosophers; i++) {philosophers[i] = new Philosopher(i, forks[i], forks[(i + 1) % numPhilosophers]);philosophers[i].start();}// 等待所有哲學家線程結束for (Philosopher philosopher : philosophers) {try {philosopher.join();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("All philosophers have finished eating. Program ends.");}
}

? 使用ReentrantLock鎖, 該類中有一個tryLock()方法, 在指定時間內獲取不到鎖對象, 就從阻塞隊列移除,不用一直等待。當獲取了左手邊的筷子之后, 嘗試獲取右手邊的筷子, 如果該筷子被其他哲學家占用, 獲取失敗, 此時就先把自己左手邊的筷子給釋放掉. 這樣就避免了死鎖問題

?方法三

奇數哲學家先左后右,偶數科學家先右后左
import java.util.concurrent.Semaphore;public class 方法四 {//奇數哲學家先左后右,偶數科學家先右后左// Five forksstatic final Semaphore[] mutex = { new Semaphore(1),new Semaphore(1),new Semaphore(1),new Semaphore(1),new Semaphore(1) };static class Philosopher extends Thread {Philosopher(int name) {super.setName(String.valueOf(name));}@Overridepublic void run() {do {try {Integer i = Integer.parseInt(super.getName());if (i % 2 == 1) {// Odd-numbered philosopher// Try to acquire the left forkmutex[i].acquire();System.out.println("哲學家" + i + "號拿起左筷子");// Try to acquire the right forkmutex[(i + 1) % 5].acquire();System.out.println("哲學家" + i + "號拿起右筷子");} else {// Even-numbered philosopher// Try to acquire the right forkmutex[(i + 1) % 5].acquire();System.out.println("哲學家" + i + "號拿起右筷子");// Try to acquire the left forkmutex[i].acquire();System.out.println("哲學家" + i + "號拿起左筷子");}// EatSystem.out.println("哲學家" + i + "號吃飯!");// Release the forksmutex[i].release();mutex[(i + 1) % 5].release();// Think (sleep for simulation)Thread.sleep(2000);} catch (InterruptedException e) {System.out.println("異常");}} while (true);}}public static void main(String[] args) {Philosopher[] threads = new Philosopher[5];for (int i = 0; i < 5; i++) {threads[i] = new Philosopher(i);}for (Philosopher i : threads) {i.start();}}
}

下面是將think和eat分開的版本:

import java.util.concurrent.Semaphore;
public class 方法四改進 {public static class 方法四 {//奇數哲學家先左后右,偶數科學家先右后左// Five forksstatic final Semaphore[] mutex = { new Semaphore(1),new Semaphore(1),new Semaphore(1),new Semaphore(1),new Semaphore(1) };static class Philosopher extends Thread {Philosopher(int name) {super.setName(String.valueOf(name));}@Overridepublic void run() {do {try {think();eat();} catch (InterruptedException e) {System.out.println("異常");}} while (true);}public void think() throws InterruptedException {Integer i = Integer.parseInt(super.getName());System.out.println("哲學家" + i + "號正在思考");// Think (sleep for simulation)Thread.sleep(2000);}public void eat() throws InterruptedException {Integer i = Integer.parseInt(super.getName());if (i % 2 == 1) {// Odd-numbered philosopher// Try to acquire the left forkmutex[i].acquire();System.out.println("哲學家" + i + "號拿起左筷子");// Try to acquire the right forkmutex[(i + 1) % 5].acquire();System.out.println("哲學家" + i + "號拿起右筷子");} else {// Even-numbered philosopher// Try to acquire the right forkmutex[(i + 1) % 5].acquire();System.out.println("哲學家" + i + "號拿起右筷子");// Try to acquire the left forkmutex[i].acquire();System.out.println("哲學家" + i + "號拿起左筷子");}// EatSystem.out.println("哲學家" + i + "號吃飯!");// Release the forksmutex[i].release();mutex[(i + 1) % 5].release();}}public static void main(String[] args) {Philosopher[] threads = new Philosopher[5];for (int i = 0; i < 5; i++) {threads[i] = new Philosopher(i);}for (Philosopher i : threads) {i.start();}}}}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/162858.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/162858.shtml
英文地址,請注明出處:http://en.pswp.cn/news/162858.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

FSCTF2023-Reverse方向題解WP。學習貼

文章目錄 [FSCTF 2023]signin[FSCTF 2023]MINE SWEEPER[FSCTF 2023]Xor[FSCTF 2023]EZRC4[FSCTF 2023]ez_pycxor[FSCTF 2023]Tea_apk[FSCTF 2023]ezcode[FSCTF 2023]ezbroke[FSCTF 2023]rrrrust!!![FSCTF2023]ezrev&#xff08;未解決&#xff09; [FSCTF 2023]signin UPX殼&am…

redis-cluster集群模式

Redis-cluster集群 1 Redis3.0引入的分布式存儲方案 2集群由多個node節點組成,redis數據分布在節點之中,在集群之中分為主節點和從節點3集群模式當中,主從一一對應,數據寫入和讀取與主從模式一樣&#xff0c;主負責寫&#xff0c;從只能讀4集群模式自帶哨兵模式&#xff0c;可…

自然資源土地管理法律法規知識競賽這么辦才高端

近些年&#xff0c;全國各地自然資源廳舉辦了土地管理法律法規知識競賽&#xff0c;從我公司承辦的這些賽事來看&#xff0c;傳統的必答題、搶答題、風險題的方式已無法激起現場比賽氣氛&#xff0c;需要更加復雜有趣的環節設置及高端競賽軟件及其配套設備加持才可以讓知識競賽…

Eigen::Matrix 轉 std::vector 親測ok!

std::vector<double> data;for (int kk 0; kk < 24; kk) {data.push_back(kk);}int n 24 / 3;typedef Eigen::Matrix<double, 3, Eigen::Dynamic> MatrixXd;//vector 轉 matrixEigen::Map<Eigen::MatrixXd> result(data.data(), 3, n);//matrix 轉 vect…

什么是交易量價差分析法?anzo Capital一分鐘講明白

交易量價差分析法是一種深入的市場分析方法&#xff0c;它主要探討了價格、價差和交易量之間的相互關系。在此過程中&#xff0c;交易量主要揭示了市場上的交易活動情況&#xff0c;而價差則反映了這些交易的價格變動。 為了更準確地理解這種關系&#xff0c;定義了交易量價差…

21. Spring擴展點之推斷構造方法

簡介 spring自己本身有推斷構造方法的邏輯&#xff0c;但同時也提供了擴展&#xff0c;SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors&#xff0c;實現該方法就可以自己定制獲取哪個構造器的邏輯&#xff0c;該擴展點spring有一個默認的實現Autow…

單元測試-java.lang.NullPointerException

報錯信息 java.lang.NullPointerException 空指針異常 空對象引用 來源 對Controller層進行單元測試&#xff0c;解決完Spring上下文報錯后繼續報錯。 解決 在測試方法執行前要為字段完成對象的注入&#xff0c;否則就報空指針異常。 測試例子 public class SysUserContr…

前端css粘性布局,頂部吸附效果(position: sticky)

sticky屬性設置 /* 設置粘性布局 */ position: sticky; /* 拖動滾動條&#xff0c;當前元素超出文檔0的位置時&#xff0c;觸發定位效果&#xff08;同級元素位置不會受影響&#xff09; */ top: 0;頁面初始效果 設置前&#xff08;滾動頁面時&#xff0c;標簽欄隨頁面滾動&a…

【深度學習】六大聚類算法快速了解

在機器學習中&#xff0c;無監督學習一直是我們追求的方向&#xff0c;而其中的聚類算法更是發現隱藏數據結構與知識的有效手段。目前如谷歌新聞等很多應用都將聚類算法作為主要的實現手段&#xff0c;它們能利用大量的未標注數據構建強大的主題聚類。本文從最基礎的 K 均值聚類…

【二叉樹進階題目】236. 二叉樹的最近公共祖先,JZ36 二叉搜索樹與雙向鏈表

二叉樹進階題目 236. 二叉樹的最近公共祖先解題思路及實現思路一思路二 JZ36 二叉搜索樹與雙向鏈表描述解題思路及實現 236. 二叉樹的最近公共祖先 給定一個二叉樹, 找到該樹中兩個指定節點的最近公共祖先。 百度百科中最近公共祖先的定義為&#xff1a;“對于有根樹 T 的兩個…

Axios 攔截器 請求攔截器 響應攔截器

請求攔截器 相當于一個關卡&#xff0c;如果滿足條件就放行請求&#xff0c;不滿足就攔截 響應攔截器 在處理結果之前&#xff0c;先對結果進行預處理&#xff0c;比如&#xff1a;對數據進行一下格式化的處理 全局請求攔截器 axios.interceptors.request.use(config > { /…

SeaTunnel及SeaTunnel Web部署指南(小白版)

現在你能搜索到的SeaTunnel的安裝。部署基本都有坑&#xff0c;官網的文檔也是見到到相當于沒有&#xff0c;基本很難找到一個適合新手小白第一次上手就能成功安裝部署的版本&#xff0c;于是就有了這個部署指南的分享&#xff0c;小主已經把可能遇到的坑都填過了&#xff0c;希…

Web前端—移動Web第五天(媒體查詢、Bootstrap、綜合案例-alloyTeam)

版本說明 當前版本號[20231122]。 版本修改說明20231122初版 目錄 文章目錄 版本說明目錄移動 Web 第五天01-媒體查詢基本寫法書寫順序案例-左側隱藏媒體查詢-完整寫法關鍵詞 / 邏輯操作符媒體類型媒體特性 媒體查詢-外部CSS 02-Bootstrap簡介使用步驟下載使用 柵格系統全局…

PTA 六度空間

“六度空間”理論又稱作“六度分隔&#xff08;Six Degrees of Separation&#xff09;”理論。這個理論可以通俗地闡述為&#xff1a;“你和任何一個陌生人之間所間隔的人不會超過六個&#xff0c;也就是說&#xff0c;最多通過五個人你就能夠認識任何一個陌生人。”如圖1所示…

大白話DDD(DDD黑話終結者)

大白話DDD&#xff08;DDD黑話終結者&#xff09; 一、吐槽的話 相信聽過DDD的人有很大一部分都不知道這玩意具體是干嘛的&#xff0c;甚至覺得它有那么一些虛無縹緲。原因之一是但凡講DDD的&#xff0c;都是一堆特別高大上的概念&#xff0c;然后冠之以一堆讓人看不懂的解釋…

Python教程73:Pandas中一維數組Series學習

創建一維數據類型Series dataNone 要轉化為Series的數據(也可用dict直接設置行索引) 若是標量則必須設置索引,該值會重復,來匹配索引的長度 indexNone 設置行索引 dtypeNone 設置數據類型(使用numpy數據類型) nameNone 設置Series的name屬性 copyFalse 不復制 (當data為ndarray…

Centos中的解壓和壓縮指令

在CentOS 7系統中&#xff0c;可以使用多種命令進行文件壓縮和解壓縮操作。以下是常見的文件壓縮和解壓命令及其用法的詳解&#xff1a; 1.tar&#xff1a;tar命令用于打包文件或目錄&#xff0c;并可選地壓縮為tar壓縮包。 創建tar壓縮包&#xff1a;tar -cvf archive.tar f…

【深度學習】神經網絡術語:Epoch、Batch Size和迭代

batchsize&#xff1a;中文翻譯為批大小&#xff08;批尺寸&#xff09;。 簡單點說&#xff0c;批量大小將決定我們一次訓練的樣本數目。 batch_size將影響到模型的優化程度和速度。 為什么需要有 Batch_Size : batchsize 的正確選擇是為了在內存效率和內存容量之間尋找最…

Postgresql源碼(116)提升子查詢案例分析

0 總結 對于SQL&#xff1a;select * from student, (select * from score where sno > 2) s where student.sno s.sno; pullup在pull_up_subqueries函數內遞歸完成&#xff0c;分幾步&#xff1a; 將內層rte score追加到上層rtbable中&#xff1a;rte1是student、rte2帶…

nginx編譯安裝

1.下載nginx&#xff1a; 地址&#xff1a;http://nginx.org/en/download.html 2.安裝依賴 安裝gcc: yum install -y gcc安裝pcre庫 yum install -y pcre pcre-devel安裝zlib庫&#xff1a; yum install -y zlib zlib-devel3.安裝nginx ./configure --prefix/usr/local/ngi…