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) ;

}

解决方案 »

  1.   

    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];
    叉子i+1还是null,没有初始化,建议先用一个循环初始化叉子。:-)
    ph[i].left=forks[i];
    ph[i].setVisible(true) ;

    }
      

  2.   

    注意上面那段代码。
    当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++){
    //...
    }
      

  3.   

    对了,还有啊,eat()是不能同步的,否则就只能有一个人吃啦。
    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) ;                }
            }
    }
      

  4.   

    谢谢北极星和阿楞改正了叉子的错误以后倒是没有异常了
    但是正如北极星所说
    1、3号哲学家始终饥饿(有时候是1、4)
    而且从理论上来说同时只能有2个哲学家吃饭的
    不可能有相邻的哲学家一起吃饭
    现在0和4同时吃饭(或者2、3)
    说明他们对于froks[0](forks[4])的同步有问题但是按照阿楞的写法
    线程0测试forks[0]的使用权
    测试forks[1]的使用权
    然后改变它们的状态
    这些都应该是被同步执行的啊
    莫非线程4也在同时测试forks[0]并获得使用权????
    还是他们根本指向的不是同一个对象???
      

  5.   

    以前我也用JAVA做过哲学家问题,没细看代码,不过这里大概有问题:synchronized void doallways(){
       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时你也知道会发生什么吧?
      

  6.   

    synchronized void doallways(){
       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 一次只唤醒一个线程,这么写两次也许可以
    不过我觉得肯定是个隐患
      

  7.   

    多些winddw(西门咳嗽)又帮助给改正了一个错误(我好粗心啊:P)我用notifyAll后的确没有相邻的哲学家吃饭了
    但是每回只能有两个固定的哲学家吃饭
    其余倒霉的哲学家都饿死了吃饭的那段改成了这样:
    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写东西都是写好了先粘到一个记事本上,然后再点发出,有好多回没了,再从记事本上粘一个过来就可以了。呵呵
      

  8.   

    To aben527cn(阿笨) :1.notifyAll() 使用一次就可以了,作用唤醒所有在等待队列里的进程2.我仔细看了一下你的代码,呵呵~~其中有逻辑问题,我觉得是错的。你不如放弃这个重新写,首先要把逻辑想清楚,可以参考一下《操作系统》清华大学出的第二版,屠立德著。那上面有问题分析和类pascal的代码。3.我觉得你的synchronized()用的位置有问题,你说的错误原因是在这里,而不是notifyAll()的问题4.我的代码不在身边,没法给你看。
      

  9.   

    还有
    winddw(西门咳嗽)
    你说的逻辑错误是指什么?
    能说清楚一点吗?
    是synchronizd()的位置吗?