package com.java.mythread;/**
 * 哲学家进餐问题的解决
 * 缺点:线程调度不是先进先出调度或优先级调度
 * */
public class Dining {
public static void main(String[] args){
Chopstick[] chops = new Chopstick[5];
Philosopher[] philos= new Philosopher[5];
for(int i= 0;i<5;i++){
chops[i] = new Chopstick();
}
for(int i= 0;i<5;i++){
philos[i] = new Philosopher(i,chops[i],chops[(i+1)%5]);
} for(int i= 0;i<5;i++){
philos[i].start();
}
}
}class Chopstick{
private boolean available;
public Chopstick(){
available = true;
}
public void takeUp(){
available = false;
}
public void putDown(){
available = true;
}
public boolean getStatus(){
return available;
}
}class Philosopher extends Thread{
public static int eatTime = 200, thinkTime = 300; 
private Chopstick left,right;
int philo_num;
public Philosopher(int No,Chopstick lc,Chopstick rc){
left = lc;
right = rc;
philo_num = No;
//setDaemon(true);
}
synchronized public void requestChops(){
while(!left.getStatus() || !right.getStatus()){
System.out.println("哲学家"+philo_num+"正在等待……");
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
left.takeUp();
right.takeUp();
}
synchronized public void returnChops(){
left.putDown();
right.putDown();
notify();
}
public void eat(){
System.out.println("哲学家"+philo_num+"正在进餐……");
  try{
sleep(eatTime);
}catch(Exception e){}
}
public void think(){
System.out.println("哲学家"+philo_num+"正在思考……");
try{
sleep(thinkTime);
}catch(Exception e){}
}
public void run(){
while(true){
this.think();
this.requestChops();
this.eat();
this.returnChops();
}
}
}最后运行结果是:
哲学家0正在思考……
哲学家3正在思考……
哲学家2正在思考……
哲学家1正在思考……
哲学家4正在思考……
哲学家0正在等待……
哲学家4正在进餐……
哲学家3正在等待……
哲学家1正在等待……
哲学家2正在进餐……
哲学家4正在思考……
哲学家2正在思考……
哲学家4正在进餐……
哲学家2正在进餐……
无论等多长时间,只有哲学家2和哲学家4线程在运行,这掌握很费解啊。
代码中当某哲学家进餐完毕,执行this.returnChops();操作时,调用notify()函数后,不是所有等待进程同时竞争资源吗?为什么会只有两个线程一直运行,其他线程出于饥饿状态?改成notifyAll()函数,结果也一样。
哪位能给下指点啊?

解决方案 »

  1.   

    没格式化没着色真难看package com.java.mythread;
    /**
     * 哲学家进餐问题的解决
     * 缺点:线程调度不是先进先出调度或优先级调度
     * */
    public class Dining {
    public static void main(String[] args){
    Chopstick[] chops = new Chopstick[5];
    Philosopher[] philos= new Philosopher[5];
    for(int i= 0;i<5;i++){
    chops[i] = new Chopstick();
    }
    for(int i= 0;i<5;i++){
    philos[i] = new Philosopher(i,chops[i],chops[(i+1)%5]);
    }for(int i= 0;i<5;i++){
    philos[i].start();
    }
    }
    }class Chopstick{
    private boolean available;
    public Chopstick(){
    available = true;
    }
    public void takeUp(){
    available = false;
    }
    public void putDown(){
    available = true;
    }
    public boolean getStatus(){
    return available;
    }
    }class Philosopher extends Thread{
    public static int eatTime = 200, thinkTime = 300;  
    private Chopstick left,right;
    int philo_num;
    public Philosopher(int No,Chopstick lc,Chopstick rc){
    left = lc;
    right = rc;
    philo_num = No;
    //setDaemon(true);
    }
    synchronized public void requestChops(){
    while(!left.getStatus() || !right.getStatus()){
    System.out.println("哲学家"+philo_num+"正在等待……");
    try {
    wait();
    } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }
    left.takeUp();
    right.takeUp();
    }
    synchronized public void returnChops(){
    left.putDown();
    right.putDown();
    notify();
    }
    public void eat(){
    System.out.println("哲学家"+philo_num+"正在进餐……");
    try{
    sleep(eatTime);
    }catch(Exception e){}
    }
    public void think(){
    System.out.println("哲学家"+philo_num+"正在思考……");
    try{
    sleep(thinkTime);
    }catch(Exception e){}
    }
    public void run(){
    while(true){
    this.think();
    this.requestChops();
    this.eat();
    this.returnChops();
    }
    }
    }
      

  2.   

    synchronized方法的问题,我觉得。因为所有的方法都共享一个锁...
      

  3.   

    LZ对同步概念模糊
    要知道,多个线程同时使用相同的资源才有同步问题
    你这里的5个线程各自调用自己的方法
    this.think();
    this.requestChops();
    this.eat();
    this.returnChops();
    跟线程和线程之间没有锁住同一个资源,你的wait和notify根本就没意义,只是自己对自己wait和notify,所以一旦进入wait,就一直等待不会被唤醒,就好像LZ的打印结果0和3,后面应该不会再出现0和3的任何打印了,因为一直停留在等待中了多个线程锁某个资源,应该synchronize(资源),然后调用 资源.wait() 资源.notify() 来达到等待和唤醒,或者在资源的方法上加上synchronized,这样wait或notify缺省就是资源的this.wait this.notify,这样才能达到同步的效果LZ再好好想想吧
      

  4.   

    本来还以为自己线程通信基本掌握了,被你这么一指点,才发现基础的概念自己还有些混淆拎不清。阿宝这段话,太强大了,一针见血,醍醐灌顶!
    现在修改哲学家类如下:
    class Philosopher extends Thread{
    public static int eatTime = 2000, thinkTime = 3000; 
    public static Chopstick[] chops = new Chopstick[5];//改动点儿
    int philo_num;
    public Philosopher(int No,Chopstick[] thechops){
    for(int i= 0;i<5;i++){
    chops[i] = thechops[i];
    }
    philo_num = No;
    //setDaemon(true);
    }
    public void requestChops(){//改动点儿
    synchronized(chops){
    if(!chops[philo_num].getStatus()||!chops[(philo_num+1)%5].getStatus())
    try {
    chops.wait();
    } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    System.out.println("哲学家"+(philo_num+1)+"准备进餐……");
    chops[philo_num].takeUp();
    chops[(philo_num+1)%5].takeUp();

    }
    public void returnChops(){
    synchronized(chops){//改动点儿
    chops[philo_num].putDown();
    chops[(philo_num+1)%5].putDown();
    System.out.println("哲学家"+(philo_num+1)+"进餐完毕……");
    chops.notifyAll();
    }
    }

    }
    现在已经能得出预期结果了:
    哲学家1准备进餐……//可同时有两个线程访问资源
    哲学家1正在进餐……
    哲学家4准备进餐……//可同时有两个线程访问资源
    哲学家4正在进餐……
    哲学家1进餐完毕……
    哲学家5准备进餐……//实现线程调度,没有出现饥饿现象
    哲学家5正在进餐……
    哲学家3准备进餐……
    哲学家1正在思考……
    哲学家2准备进餐……
    哲学家2正在进餐……
    哲学家3正在进餐……不知这样写,会不会还有什么不足之处,或者还有更好的更清晰的实现结构还请多多指教!
      

  5.   

     不会出现两个线程同时访问资源. 
    一位哲学家(假设1号)就餐时(访问资源),其前后两位(2和5) 因得不到筷子,会在"对象wait 池"里阻塞,另两位中的一位(假设3)能得到筷子,但不能得到同步锁,是在"对象lock池阻塞".(4号与2和5一样). 3号要等到1号释放锁后,才会进入就绪状态,可以运行.
    此时2号或5号有一位会被 notify()唤醒,而进入对象lock 池. 一旦得到同步锁,即可运行(去吃饭).