关于Java多线程的经典问题:哲学家就餐问题。以前在网上找过很多例子,执行的效果都不尽人意。于是阅读了一些多线程的书写了一个解决案。
因为接触多线程时间不长,写出来的东西还请大牛们多多指教。
问题描述:哲学家就餐问题可以这样表述,假设有五位哲学家围坐在一张圆形餐桌旁,做以下两件事情之一:吃饭,或者思考。吃东西的时候,他们就停止思考,思考的时候也停止吃东西。餐桌中间有一大碗意大利面,每两个哲学家之间有一只餐叉。因为用一只餐叉很难吃到意大利面,所以假设哲学家必须用两只餐叉吃东西。他们只能使用自己左右手边的那两只餐叉。哲学家就餐问题有时也用米饭和筷子而不是意大利面和餐叉来描述,因为很明显,吃米饭必须用两根筷子。
哲学家从来不交谈,这就很危险,可能产生死锁,每个哲学家都拿着左手的餐叉,永远都在等右边的餐叉(或者相反)。即使没有死锁,也有可能发生资源耗尽。例如,假设规定当哲学家等待另一只餐叉超过五分钟后就放下自己手里的那一只餐叉,并且再等五分钟后进行下一次尝试。这个策略消除了死锁(系统总会进入到下一个状态),但仍然有可能发生“活锁”。如果五位哲学家在完全相同的时刻进入餐厅,并同时拿起左边的餐叉,那么这些哲学家就会等待五分钟,同时放下手中的餐叉,再等五分钟,又同时拿起这些餐叉。
在实际的计算机问题中,缺乏餐叉可以类比为缺乏共享资源。一种常用的计算机技术是资源加锁,用来保证在某个时刻,资源只能被一个程序或一段代码访问。当一个程序想要使用的资源已经被另一个程序锁定,它就等待资源解锁。当多个程序涉及到加锁的资源时,在某些情况下就有可能发生死锁。例如,某个程序需要访问两个文件,当两个这样的程序各锁了一个文件,那它们都在等待对方解锁另一个文件,而这永远不会发生。
public class PerThread extends Thread {
public static void main(String... arg){
Copsticks cop = new Copsticks();
for(int i = 0; i < 5; i++){
PerThread per = new PerThread(i, cop);
per.start();
}
}
private int index;
private int count = 0;
private boolean lefCop = false;
private boolean rightCop = false;
private Copsticks cop = new Copsticks();
public PerThread(int index, Copsticks cop){
this.index = index;
this.cop = cop;
}
public void run() {
// 默认吃5次以后哲学家吃饱
while (count < 5) {
// 哲学家在思考
thinking();
// 监测筷子并获取筷子,否则等待
takeCopsticks();
// 获取筷子后吃饭
eat();
// 吃完后放下筷子
putCopsticks();
}
System.out.println("哲学家" + index + ":吃饱了!");
}
// 哲学家思考
private void thinking(){
try {
System.out.println("哲学家" + index + ":在思考。。。。");
sleep((int)Math.abs(Math.random() * 1000));
System.out.println("哲学家" + index + ":思考结束!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 哲学家吃饭
private void eat(){
try {
System.out.println("哲学家" + index + ":在吃饭。。。。");
count++;
sleep((int)Math.abs(Math.random() * 1000));
System.out.println("哲学家" + index + ":吃饭结束!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
public boolean isLefCop() {
return lefCop;
}
public void setLefCop(boolean lefCop) {
this.lefCop = lefCop;
}
public boolean isRightCop() {
return rightCop;
}
public void setRightCop(boolean rightCop) {
this.rightCop = rightCop;
}
// 获取筷子
public void takeCopsticks(){
// synchronized关键字给共享资源Copsticks加锁
synchronized(cop){
PerThread per = (PerThread)Thread.currentThread();
int index = per.getIndex();
while(cop.used[index] && cop.used[(index + 1) % 5]){
try {
System.out.println("哲学家" + index + ":无法获得筷子!在等待。。。");
// 执行共享对象的wait()发放,让线程在cop对象上等待
cop.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
cop.used[index] = true;
System.out.println("哲学家" + index + ":获得左快子!");
per.setLefCop(true);
cop.used[(index + 1) % 5] = true;
System.out.println("哲学家" + index + ":获得右快子!");
per.setRightCop(true);
}
}
// 释放筷子
public void putCopsticks(){
// synchronized关键字给共享资源Copsticks加锁
synchronized(cop){
PerThread per = (PerThread)Thread.currentThread();
int index = per.getIndex();
cop.used[index] = false;
System.out.println("哲学家" + index + ":放下左快子!");
per.setLefCop(false);
cop.used[(index + 1) % 5] = false;
System.out.println("哲学家" + index + ":放下右快子!");
per.setRightCop(false);
// 执行共享对象cop的notifyAll()方法,唤醒在这个对象cop上等待的线程
cop.notifyAll();
}
}
}
/**
*筷子类
*/
class Copsticks{
public boolean[] used = {false,false,false,false,false};
}