1965年斜脂,荷蘭計算機(jī)科學(xué)家圖靈獎得主Edsger Wybe Dijkstra提出并解決了一個他稱之為哲學(xué)家進(jìn)餐的同步問題艾恼。這個問題可以簡單地描述如下:五個哲學(xué)家圍坐在一張圓桌周圍,每個哲學(xué)家面前都有一盤通心粉。由于通心粉很滑,所以需要兩把叉子才能夾住。相鄰兩個盤子之間放有一把叉子如下圖所示蜕该。哲學(xué)家的生活中有兩種交替活動時段:即吃飯和思考。當(dāng)一個哲學(xué)家覺得餓了時洲鸠,他就試圖分兩次去取其左邊和右邊的叉子堂淡,每次拿一把,但不分次序扒腕。如果成功地得到了兩把叉子绢淀,就開始吃飯,吃完后放下叉子繼續(xù)思考袜匿。 ??把上面問題中的哲學(xué)家換成線程更啄,把叉子換成競爭的臨界資源,上面的問題就是線程競爭資源的問題居灯。如果沒有經(jīng)過精心的設(shè)計祭务,系統(tǒng)就會出現(xiàn)死鎖、活鎖怪嫌、吞吐量下降等問題
Paste_Image.png
package threadTest;
import java.util.concurrent.Semaphore;
public class test01 {
public static void main(String[] args) {
String[] names = { "駱昊", "王大錘", "張三豐", "楊過", "李莫愁" }; // 5位哲學(xué)家的名字
// ExecutorService es = Executors.newFixedThreadPool(AppContext.NUM_OF_PHILO); // 創(chuàng)建固定大小的線程池
// for(int i = 0, len = names.length; i < len; ++i) {
// es.execute(new Philosopher(i, names[i])); // 啟動線程
// }
// es.shutdown();
for(int i = 0, len = names.length; i < len; ++i) {
new Thread(new Philosopher(i, names[i])).start();
}
}
}
class AppContext{
public static final int NUM_OF_FORKS=5; //叉子數(shù)量(資源)
public static final int NUM_OF_PHILO=5; //哲學(xué)家數(shù)量(線程)
public static Semaphore[] forks; //叉子的信號量
public static Semaphore counter; //哲學(xué)家的信號量
static{
forks=new Semaphore[NUM_OF_FORKS];
for(int i=0,len=forks.length;i<len;i++){
forks[i]=new Semaphore(1); //每個叉子的信號量為1
}
counter=new Semaphore(NUM_OF_PHILO-1); //如果有n個哲學(xué)家义锥,最多只允許n-1人同時取叉子
}
/**
* 取得叉子
* @param index 第幾個哲學(xué)家
* @param leftFirst 是否先取得左邊的叉子
* @throws InterruptedException
*/
public static void putOnFork(int index,boolean leftFirst)throws InterruptedException{
if(leftFirst){
forks[index].acquire();
forks[(index+1)%NUM_OF_PHILO].acquire();
}else{
forks[(index+1)%NUM_OF_PHILO].acquire();
forks[index].acquire();
}
}
/**
* 放回叉子
* @param index 第幾個哲學(xué)家
* @param leftFirst 是否先放回左邊的叉子
* @throws InterruptedException
*/
public static void putDownFork(int index,boolean leftFirst)throws InterruptedException{
if(leftFirst){
forks[index].release();
forks[(index+1)%NUM_OF_PHILO].release();
}else{
forks[(index+1)%NUM_OF_PHILO].release();
forks[index].release();
}
}
}
/**
* 哲學(xué)家
*
*/
class Philosopher implements Runnable {
private int index; // 編號
private String name; // 名字
public Philosopher(int index, String name) {
this.index = index;
this.name = name;
}
@Override
public void run() {
while(true) {
try {
AppContext.counter.acquire();
boolean leftFirst = index % 2 == 0;
AppContext.putOnFork(index, leftFirst);
System.out.println(name + "正在吃意大利面(通心粉)..."); // 取到兩個叉子就可以進(jìn)食
AppContext.putDownFork(index, leftFirst);
AppContext.counter.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}