前言:
生產者-消費者模型和哲學家就餐問題是多線程中比較經典的兩個問題.通過這兩個問題,可以很好地瞭解和實踐下java多線程的基礎知識.
哲學家就餐問題:
有五個哲學家,他們的生活方式是交替地進行思考和進餐。他們共用一張圓桌,分別坐在五張椅子上。
在圓桌上有五個碗和五支筷子,平時一個哲學家進行思考,飢餓時便試圖取用其左、右最靠近他的筷子,只有在他拿到兩支筷子時才能進餐。進餐完畢,放下筷子又繼續思考。
對java多線程不熟悉的可以先看下生產者-消費者模型是怎麼實現的,然後再獨立實現哲學家就餐問題.
解決方案1:
哲學家要進餐時,要麼同時拿起兩支筷子,要麼一支筷子都不拿.
代碼實現:
package com.example.demo.thread;
public class PhilosopherQuestion {
// chopsticks
private boolean[] used = new boolean[] { false, false, false, false, false };
private static String LOCK = "lock";
public static void main(String[] args) {
PhilosopherQuestion philosopherQuestion = new PhilosopherQuestion();
philosopherQuestion.new Philosopher(0).start();
philosopherQuestion.new Philosopher(1).start();
philosopherQuestion.new Philosopher(2).start();
philosopherQuestion.new Philosopher(3).start();
philosopherQuestion.new Philosopher(4).start();
}
class Philosopher extends Thread {
private int num;
public Philosopher(int num) {
this.num = num;
}
public void eating() {
System.out.println("my num is " + num + " , I am eating...");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void thinking() {
System.out.println("my num is " + num + ", I am thinking...");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//拿筷子時只要有一個筷子已經被佔用,就要放棄拿筷子,並釋放鎖進入等待狀態
//得到通知後,再進入就緒狀態,重新競爭鎖
public void takeChopsticks(){
synchronized(LOCK) {
if (used[num] || used[(num + 1) % 5]) {
try {
LOCK.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//拿到兩支筷子了
used[num] = true;
used[(num + 1) % 5] = true;
}
}
//放下筷子時,也要申請鎖,然後通知所有等待的線程
public void putDownChopsticks() {
synchronized(LOCK) {
used[num] = false;
used[(num + 1) % 5] = false;
System.out.println("my num is " + num + " , I have finished...");
LOCK.notifyAll();
}
}
@Override
public void run() {
while(true) {
thinking();
takeChopsticks();
eating();
putDownChopsticks();
}
}
}
}
運行結果:
my num is 0, I am thinking...
my num is 3, I am thinking...
my num is 2, I am thinking...
my num is 1, I am thinking...
my num is 4, I am thinking...
my num is 0 , I am eating...
my num is 3 , I am eating...
my num is 3 , I have finished...
my num is 3, I am thinking...
my num is 1 , I am eating...
my num is 2 , I am eating...
my num is 4 , I am eating...
my num is 0 , I have finished...
my num is 0, I am thinking...
my num is 1 , I have finished...
my num is 1, I am thinking...
my num is 4 , I have finished...
my num is 0 , I am eating...
my num is 4, I am thinking...
my num is 2 , I have finished...
my num is 2, I am thinking...
my num is 3 , I am eating...
my num is 0 , I have finished...
my num is 0, I am thinking...
my num is 1 , I am eating...
my num is 3 , I have finished...
my num is 3, I am thinking...
my num is 2 , I am eating...
my num is 4 , I am eating...
my num is 1 , I have finished...
my num is 1, I am thinking...
my num is 2 , I have finished...
my num is 2, I am thinking...
my num is 4 , I have finished...
my num is 4, I am thinking...
my num is 0 , I am eating...
my num is 3 , I am eating...
my num is 0 , I have finished...
my num is 0, I am thinking...
my num is 1 , I am eating...
my num is 4 , I am eating...
my num is 3 , I have finished...
my num is 2 , I am eating...
my num is 3, I am thinking...
my num is 1 , I have finished...
my num is 2 , I have finished...
my num is 2, I am thinking...
my num is 0 , I am eating...
my num is 1, I am thinking...
my num is 3 , I am eating...
my num is 4 , I have finished...
my num is 4, I am thinking...
my num is 3 , I have finished...
my num is 3, I am thinking...
my num is 0 , I have finished...
my num is 0, I am thinking...
my num is 4 , I am eating...
my num is 2 , I am eating...
my num is 1 , I am eating...
my num is 4 , I have finished...
my num is 4, I am thinking...
my num is 0 , I am eating...
my num is 3 , I am eating...
my num is 1 , I have finished...
my num is 1, I am thinking...
my num is 2 , I have finished...
my num is 2, I am thinking...
my num is 0 , I have finished...
my num is 0, I am thinking...
my num is 3 , I have finished...
my num is 4 , I am eating...
my num is 2 , I am eating...
my num is 3, I am thinking...
my num is 4 , I have finished...
my num is 4, I am thinking...
my num is 2 , I have finished...
my num is 0 , I am eating...
my num is 1 , I am eating...
my num is 3 , I am eating...
my num is 2, I am thinking...
my num is 0 , I have finished...
my num is 0, I am thinking...
my num is 4 , I am eating...
my num is 3 , I have finished...
my num is 1 , I have finished...
my num is 3, I am thinking...
my num is 2 , I am eating...
my num is 1, I am thinking...
my num is 4 , I have finished...
my num is 4, I am thinking...
my num is 0 , I am eating...
my num is 2 , I have finished...
my num is 2, I am thinking...
my num is 3 , I am eating...
my num is 0 , I have finished...
my num is 0, I am thinking...
my num is 3 , I have finished...
my num is 4 , I am eating...
my num is 2 , I am eating...
my num is 3, I am thinking...
my num is 1 , I am eating...
my num is 4 , I have finished...
my num is 4, I am thinking...
my num is 2 , I have finished...
my num is 0 , I am eating...
my num is 1 , I have finished...
my num is 3 , I am eating...
my num is 2, I am thinking...
my num is 1, I am thinking...
解決方案2:
給筷子編號,哲學家將要進餐時,要先從小號的開始拿.
代碼實現:
package com.example.demo.thread;
public class PhilosopherQuestion {
// chopsticks
private boolean[] used = new boolean[] { false, false, false, false, false };
private static String LOCK = "lock";
public static void main(String[] args) {
PhilosopherQuestion philosopherQuestion = new PhilosopherQuestion();
philosopherQuestion.new Philosopher1(0).start();
philosopherQuestion.new Philosopher1(1).start();
philosopherQuestion.new Philosopher1(2).start();
philosopherQuestion.new Philosopher1(3).start();
philosopherQuestion.new Philosopher1(4).start();
}
class Philosopher1 extends Thread {
private int num;
public Philosopher1(int num) {
this.num = num;
}
public void eating() {
System.out.println("my num is " + num + " , I am eating...");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void thinking() {
System.out.println("my num is " + num + ", I am thinking...");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void takeChopsticks() {
synchronized (LOCK) {
int min = Math.min(num, (num + 1) % 5);
int max = Math.max(num, (num + 1) % 5);
if (!used[min]) {//先嚐試拿小號筷子,失敗則進入等待狀態,並釋放鎖
used[min] = true;
if(!used[max]) {//成功拿到小號筷子後,嘗試拿大號筷子,失敗,則進入等待狀態,並釋放鎖,但是沒有釋放小號筷子
used[max] = true;
} else {
try {
LOCK.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} else {
try {
LOCK.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//放下筷子後,通知其他等待線程
public void putDownChopsticks() {
synchronized(LOCK) {
used[num] = false;
used[(num + 1) % 5] = false;
System.out.println("my num is " + num + " , I have finished...");
LOCK.notifyAll();
}
}
@Override
public void run() {
while(true) {
thinking();
takeChopsticks();
eating();
putDownChopsticks();
}
}
}
}
輸出爲:
my num is 1, I am thinking...
my num is 0, I am thinking...
my num is 4, I am thinking...
my num is 3, I am thinking...
my num is 2, I am thinking...
my num is 1 , I am eating...
my num is 3 , I am eating...
my num is 1 , I have finished...
my num is 1, I am thinking...
my num is 0 , I am eating...
my num is 3 , I have finished...
my num is 3, I am thinking...
my num is 2 , I am eating...
my num is 4 , I am eating...
my num is 0 , I have finished...
my num is 1 , I am eating...
my num is 0, I am thinking...
my num is 2 , I have finished...
my num is 2, I am thinking...
my num is 4 , I have finished...
my num is 4, I am thinking...
my num is 3 , I am eating...
my num is 1 , I have finished...
my num is 0 , I am eating...
my num is 1, I am thinking...
my num is 3 , I have finished...
my num is 3, I am thinking...
my num is 4 , I am eating...
my num is 2 , I am eating...
my num is 0 , I have finished...
my num is 0, I am thinking...
my num is 3 , I am eating...
my num is 4 , I have finished...
my num is 4, I am thinking...
my num is 1 , I am eating...
my num is 2 , I have finished...
my num is 2, I am thinking...
my num is 3 , I have finished...
my num is 1 , I have finished...
my num is 3, I am thinking...
my num is 2 , I am eating...
my num is 1, I am thinking...
my num is 0 , I am eating...
my num is 2 , I have finished...
my num is 2, I am thinking...
my num is 4 , I am eating...
my num is 3 , I am eating...
my num is 0 , I have finished...
my num is 0, I am thinking...
my num is 1 , I am eating...