for(i=0;i<5;i++){
//哲学家就坐
forks[i]=new fork();
ph[i]=new philosopher(i);
//确定每个哲学家的左右叉子
if(i==4) ph[i].right=forks[0];
else ph[i].right=forks[i+1];
ph[i].left=forks[i];
ph[i].setVisible(true) ;
}
//哲学家就坐
forks[i]=new fork();
ph[i]=new philosopher(i);
//确定每个哲学家的左右叉子
if(i==4) ph[i].right=forks[0];
else ph[i].right=forks[i+1];
ph[i].left=forks[i];
ph[i].setVisible(true) ;
}
//哲学家就坐
forks[i]=new fork();
ph[i]=new philosopher(i);
//确定每个哲学家的左右叉子
if(i==4) ph[i].right=forks[0];
else ph[i].right=forks[i+1];
叉子i+1还是null,没有初始化,建议先用一个循环初始化叉子。:-)
ph[i].left=forks[i];
ph[i].setVisible(true) ;
}
当i=0时fork[0]=new fork();
然后
ph[0].right=forks[1];
而这时forks[1]尚未被初始化,所以,forks[1]=null即ph[0].right=null
所以除了第一个Thread之外其余一律会抛出NullPointerExcetion异常。
首先将forks初始化既可解决问题,如下:
for(i=0;i<5;i++) forks[i]=new fork();
for(i=9;i<5;i++){
//...
}
package com.openflex.Arts;/**
* <p>Title: </p>
* <p>Description: </p>
* <p>Copyright: Copyright (c) 2001</p>
* <p>Company: </p>
* @author unascribed
* @version 1.0
*/import java.lang.Runnable;
import java.awt.Frame;
import java.awt.event.*;//叉子
class fork { //叉子是否在使用
boolean inuse;
//初始化
fork(){
inuse = false;
}
}
//哲学家
class philosopher extends Frame implements Runnable{
//哲学家的位置和号码
int x,y,width,height,number;
fork left ;
fork right ;
//初始化
philosopher(int number){
super();
setBounds(150*number,100,150,200);
this.number = number;
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
dispose();
System.exit(0);
}
});
new Thread(this).start();
}
//思考的方法
void think(){
this.setSize(150,200);
this.setTitle("thinking");
}
//吃饭的方法
void eat(){
this.setSize(150,400);
this.setTitle("eating");
}
//开始思考了
public void run(){
if(this.right==null||this.left==null){
System.out.println("Forks null.");
return;
}
while(true){
this.think();
try { Thread.sleep(3000); } catch(Exception e) {};
doallways();
}
}
//饿了,开始找叉子和吃饭(这里有问题,但是我不知道是什么)
void doallways(){
synchronized (this){
if(this.right.inuse)//报错提示说这行有错,似乎是没有初始化就使用
try { wait(); } catch(InterruptedException e) {};
if(this.left.inuse)
try { wait(); } catch (InterruptedException e){} ;
this.right.inuse = true;
this.right.inuse = true;
}
this.eat();
try { Thread.sleep(3000); } catch(Exception e) {};
synchronized (this){
this.right.inuse = false;
this.left.inuse = false;
}
//notify();
//notify();
}
}//主类,执行
public class Philosophers{
public static void main(String args[]){
//来了5个带叉子的哲学家
int i;
fork[] forks = new fork[5];
philosopher[] ph = new philosopher[5];
for(i=0;i<5;i++){
forks[i]=new fork();
}
for(i=0;i<5;i++){
//哲学家就坐
ph[i]=new philosopher(i);
//确定每个哲学家的左右叉子
if(i==4) ph[i].right=forks[0];
else ph[i].right=forks[i+1];
ph[i].left=forks[i];
ph[i].setVisible(true) ; }
}
}
但是正如北极星所说
1、3号哲学家始终饥饿(有时候是1、4)
而且从理论上来说同时只能有2个哲学家吃饭的
不可能有相邻的哲学家一起吃饭
现在0和4同时吃饭(或者2、3)
说明他们对于froks[0](forks[4])的同步有问题但是按照阿楞的写法
线程0测试forks[0]的使用权
测试forks[1]的使用权
然后改变它们的状态
这些都应该是被同步执行的啊
莫非线程4也在同时测试forks[0]并获得使用权????
还是他们根本指向的不是同一个对象???
if(this.right.inuse)//报错提示说这行有错,似乎是没有初始化就使用
try { wait(); } catch(InterruptedException e) {};
if(this.left.inuse)
try { wait(); } catch (InterruptedException e){};
this.right.inuse = true;//这里代码你程序里是不是也是错的?
this.right.inuse = true;//好歹应该给left一个吧?
this.eat();
try { Thread.sleep(3000); } catch(Exception e) {};
this.right.inuse = false;
this.left.inuse = false;
notify();
notify();
}其实我觉得就是你那里马虎造成的,而且你这个程序有bug啊,呵呵~
第4个哲学家(0是第一个)不应该放在循环里创建,他拿叉子的顺序应该和其他人
相反,别人都是先拿右手叉子他就要先拿左手,要不然会有永久饥饿状态发生
造成死锁,毕竟你没有设置线程优先级和思考就餐的时间~
另外用notifyAll()好些,notify()只唤醒在等待队列最上的线程(如果你用linux就当我没说!这是由系统调度方式决定的),这样就存在线程刚被唤醒就又被阻塞重新回到等待队列,当队列是FILO时你也知道会发生什么吧?
if(this.right.inuse)//报错提示说这行有错,似乎是没有初始化就使用
try { wait(); } catch(InterruptedException e) {};
if(this.left.inuse)
try { wait(); } catch (InterruptedException e){} ;
this.right.inuse = true; //好歹也要给left一个吧?
this.right.inuse = true; //应该是这里的缘故
this.eat();
try { Thread.sleep(3000); } catch(Exception e) {};
this.right.inuse = false;
this.left.inuse = false;
notify();
notify();
}我以前也做过这个,感觉你写的有点问题,会引起死锁
倒霉的是刚才写了好多没发出去,没心情再写了:(
有兴趣讨论讨论的话 [email protected] 是我信箱
顺便说一下应该用 notifyAll() 吧?
notify 一次只唤醒一个线程,这么写两次也许可以
不过我觉得肯定是个隐患
但是每回只能有两个固定的哲学家吃饭
其余倒霉的哲学家都饿死了吃饭的那段改成了这样:
void doallways(){
synchronized(this){
if(this.right.inuse)
try { wait(); } catch(InterruptedException e) {};
if(this.left.inuse)
try { wait(); } catch (InterruptedException e){};
this.right.inuse = true;
this.left.inuse = true;
}
this.eat();
try { Thread.sleep(3000); } catch(Exception e) {};
synchronized(this){
this.right.inuse = false;
this.left.inuse = false;
notifyAll();
notifyAll();//这里我用了两个notifyAll(),因为我不知道两个
//资源是否要用两个notifyAll()呢?还是一
//个notifyAll就可以释放所有阻塞的线程?
}
}要是找运行情况来看,似乎是notifyAll()这里有问题,阻塞的线程并没有获得唤醒(或者是唤醒了但是由于某种原因没有获得资源?)P.S: winddw(西门咳嗽),我现在在CSDN写东西都是写好了先粘到一个记事本上,然后再点发出,有好多回没了,再从记事本上粘一个过来就可以了。呵呵
winddw(西门咳嗽)
你说的逻辑错误是指什么?
能说清楚一点吗?
是synchronizd()的位置吗?