【问题标题】:Dining philosophers - I spoke to all, just one listens就餐哲学家——我对所有人说话,只有一个人在听
【发布时间】:2015-08-08 16:25:31
【问题描述】:

我正在实现哲学家就餐问题,我自己也遇到了一个问题,我不知道是什么原因,所以我在这里。

晚饭后我告诉他们离开,我想强迫他们创建报告,因为那是他们生命的下一个阶段。当我这样做时,所有人都会回应,但只有一个行动:

控制台输出:

0 >> I was told to stop.
1 >> I was told to stop.
2 >> I was told to stop.
3 >> I was told to stop.
4 >> I was told to stop.
philosopher 0 reporting
report filed, total 1



这是哲学家班:

import java.util.ArrayList;
import java.util.List;

public class Philosopher implements Runnable {

    // 1 - eating
    // 2 - thinking
    // 3 - waiting
    // 4 - reporting
    private int id;
    private int state;
    private int eating;
    private int waiting;
    private int thinking;
    private int consecutiveWaitingTime;

    private long thinkingTime;
    private long initialDelay;
    private long eatingTime;
    private long waitingTime;

    private boolean thePartyIsOn;   
    private boolean leftInHand;
    private boolean rightInHand;
    private boolean speech = false;
    private boolean timeLineLogSent = false;

    private DiningRoom host;

    private Fork left;
    private Fork right; 

    private List<LogBookRecord> timelineLog;    

    public Philosopher(int idn, DiningRoom host){
        timelineLog = new ArrayList<LogBookRecord>();
        this.host = host;
        thePartyIsOn = true;
        leftInHand = false;
        rightInHand = false;                
        thinkingTime = 100l; //miliseconds
        eatingTime = 300l;
        waitingTime = 50l;
        initialDelay = idn*70; 
        consecutiveWaitingTime = 0;
        eating = 0;
        waiting = 0;
        thinking = 0;
        state = 3;      
        id = idn;       
    }   


    @Override
    public void run(){  
        if(speech){ System.out.println("philosopher " +id+ "!"); }
        while(thePartyIsOn){
            try { Thread.sleep(initialDelay); } 
            catch (InterruptedException e) { e.printStackTrace(); }
            log("Started dining with delay of " +initialDelay+ " miliseconds...");
            while(true){
                switch(state){
                case 1:  // eating
                    if(speech){ System.out.println("philosopher " +id+ " eating"); }
                    log("Eating...");
                    eating++;
                    try { Thread.sleep(eatingTime); } 
                    catch (InterruptedException e) { e.printStackTrace(); }
                    releaseForks(); 
                    state = 2;
                    break;
                case 2:  // thinking
                    if(speech){ System.out.println("philosopher " +id+ " thinking"); }
                    log("Thinking...");
                    thinking++;
                    try { Thread.sleep(thinkingTime);} 
                    catch (InterruptedException e1) { e1.printStackTrace(); }
                    state = 3;  
                    break;
                case 3: // waiting
                    if(speech){ System.out.println("philosopher " +id+ " waiting"); }
                    tryEating();
                    log("Waiting...");
                    waiting++;
                    if(consecutiveWaitingTime > 20 && !host.isStarvationAlertOn()){ 
                        host.pressStarvationAlertButton(id);                        
                    }
                    try { Thread.sleep(waitingTime); }
                    catch (InterruptedException e) { e.printStackTrace(); } 
                    break;
                case 4: // reporting
                    if(!timeLineLogSent){ 
                        System.out.println("philosopher " +id+ " reporting");
                        log("Creating final report...");
                        host.fileReport(id, timelineLog); 
                        timeLineLogSent = true;
                        thePartyIsOn = false;
                    }
                    break;              
                }
            }
        }
        if(speech){ System.out.println("PHILOSOPHER " +id+ ": My task is done. Good bye."); }
    }

    private void tryEating() {
        if(!leftInHand){ left.take(); leftInHand = true; }
        else if(!rightInHand){ right.take(); rightInHand = true;}
        else{ state = 1; }      
    }

    private void releaseForks() {       
        left.release();
        leftInHand = false;
        right.release();
        rightInHand = false;
    }

    private void log(String log){ timelineLog.add(new LogBookRecord(System.nanoTime(), ("PHILOSOPHER " +id+ ": " +log))); }

    public synchronized void reportTime(){ 
        System.out.println(id+ " >> I was told to stop.");
        log("I was told to stop!");
        log("eating: " +eating);
        log("waiting: " +waiting);
        log("thinking: " +thinking);
        state = 4; 
    }
    public void setLeftFork(Fork fl) {  left = fl; }
    public void setRightFork(Fork fr){ right = fr; }
}



DiningRoom 类:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import utilities.FileHandler;

public class DiningRoom {
    private String filename = "PhilosophersFeastReport.txt";    
    Philosopher[] guests;
    Fork[] forks;   
    private int guestsQty = 5;
    private int guestsLeftTheBuilding;
    public boolean starvationAlert;
    private List<LogBookRecord> diningRoomLog;
    private FileHandler fh;
    private int reportsFiled;   
    private long napTime;
    private boolean timeIsUp;
    Timer timer;
    int secondsLeft = 5;

    public DiningRoom(){
        timeIsUp = false;
        timer = new Timer();            
        napTime = 500l;
        m("Constructing the dining room...");               
        reportsFiled = 0;
        guestsLeftTheBuilding = 0;      
        diningRoomLog = new ArrayList<LogBookRecord>();

        m("Creating file for the report...");
        fh = new FileHandler();
        fh.createFile(filename);
        m("File [" +filename+ "] created...");

        starvationAlert = false;
        m("The guests are in...");
        guests = new Philosopher[guestsQty];
        forks = new Fork[guestsQty];

        m("Assigning forks...");
        prepareTheScene(guests,forks);

        m("Starting threads...");
        oficiallyStartTheDinner(guests);

        relax();
    }


    private void oficiallyStartTheDinner(Philosopher[] phs) {           
        timer.scheduleAtFixedRate(new TimerTask(){
            @Override
            public void run() {
                secondsLeft--;
                m(secondsLeft+ " seconds left..."); 
                if(secondsLeft <= 0){ 
                    timeIsUp = true;
                    this.cancel(); 
                    }
            }           
        }, 1000, 1000);     

        for(Philosopher p : phs){
            Thread t = new Thread(p);
            t.start();
        }
    }


    private void prepareTheScene(Philosopher[] table, Fork[] cutlery){
        m("Preparing the scene...");

        Fork f0 = new Fork();
        Philosopher ph0 = new Philosopher(0,this);      
        Fork f1 = new Fork();
        Philosopher ph1 = new Philosopher(1,this);
        Fork f2 = new Fork();
        Philosopher ph2 = new Philosopher(2,this);
        Fork f3 = new Fork();
        Philosopher ph3 = new Philosopher(3,this);
        Fork f4 = new Fork();
        Philosopher ph4 = new Philosopher(4,this);

        ph0.setRightFork(f0);
        ph0.setLeftFork(f1);        
        ph1.setRightFork(f1);
        ph1.setLeftFork(f2);        
        ph2.setRightFork(f2);
        ph2.setLeftFork(f3);        
        ph3.setRightFork(f3);
        ph3.setLeftFork(f4);        
        ph4.setRightFork(f4);
        ph4.setLeftFork(f0);    

        table[0] = ph0;
        table[1] = ph1;
        table[2] = ph2;
        table[3] = ph3;
        table[4] = ph4;

        cutlery[0] = f0;
        cutlery[1] = f1;
        cutlery[2] = f2;
        cutlery[3] = f3;
        cutlery[4] = f4;
    }


    private void relax(){
        boolean j = true;
        boolean k = true;
        while(reportsFiled != 5 && guestsLeftTheBuilding != 5){  // to be changed for correct conditions
            if(!timeIsUp){
                try {
                    Thread.sleep(napTime);
                    m("ZzZzZzZz...");
                }catch (InterruptedException e) {               
                    e.printStackTrace();
                }           
                if(j){ m("\tManagement is relaxing now..."); j = false; }   
                if(timeIsUp){               
                    if(k){ tellTheGuestsItIsTimeToGo(); k = false;}
                //break; 
                }
            }
        }


        m("Sorting the report log");
        Collections.sort(diningRoomLog);
        List<String> readyList = prepareTheList(diningRoomLog); 

        m("Calling file parser...");
        fh.writeToFile(filename, readyList);
        m("All done");
    }

    private List<String> prepareTheList(List<LogBookRecord> log) {
        m("Converting the log for file parser...");
        List<String> l = new ArrayList<String>();
        for(LogBookRecord lbr : log){
            l.add(lbr.toString());
        }
        return l;
    }

    private void tellTheGuestsItIsTimeToGo() {
        for(Philosopher p : guests){
            p.reportTime();
        }
    }       

    public static void main(String[] args){
        new DiningRoom();
    }

    public synchronized void fileReport(int philosopherId, List<LogBookRecord> report){
        diningRoomLog.add(new LogBookRecord(System.nanoTime(), "DINING ROOM: PHILOSOPHER " +philosopherId+ " filed a report"));
        diningRoomLog.addAll(report);
        reportsFiled++;
        m("report filed, total " +reportsFiled);
    }

    public synchronized void philosopherLeaving(int philosopherId){
        diningRoomLog.add(new LogBookRecord(System.nanoTime(), "PHILOSOPHER " +philosopherId+ " just left."));
    }
    public synchronized boolean isStarvationAlertOn(){ return starvationAlert; }

    public synchronized void pressStarvationAlertButton(int starvingPhilosopherId){
        diningRoomLog.add(new LogBookRecord(System.nanoTime(), "**** Philosopher "+starvingPhilosopherId+ " raised starvation alert!"));
        tellTheGuestsItIsTimeToGo();
        m("Philosopher " +starvingPhilosopherId+ " flipped starvation alert...");
    }   

    private void m(String s){ System.out.println(s); }
}

【问题讨论】:

  • 当您发出停止指令时,您是否检查了每个哲学家的状态?
  • 您的代码非常复杂,无法编译。如果您希望有人检查它,我建议您创建一个MVCE:定义“Fork”并用常规 printlns 替换 LogBook 内容。我怀疑问题出在我自己的日志记录中。
  • 至于 LogBookRecord,是的,我忘记了,如果我记得的话,我会把它包括在内。我现在不在家所以不能这样做,但我确定日志不是问题。

标签: java multithreading runnable dining-philosopher


【解决方案1】:

我破解了你的代码,让它运行,然后在上面运行一个调试器。你有两个问题。首先是您实际上并没有实现餐饮哲学家的算法。您只是尝试在没有任何检查或释放算法的情况下获取锁(Fork)。在我的调试器中,至少有两个线程卡在tryEating() 中,两个线程都卡在等待永远不会释放的锁。

// broken: no checks before taking lock
private void tryEating() {
    if(!leftInHand){ left.take(); leftInHand = true; }
    else if(!rightInHand){ right.take(); rightInHand = true;}
    else{ state = 1; }      
}

leftInHandrightInHand 这两个变量是instance 变量。他们只检查是否有锁。他们不检查其他哲学家是否有锁。

第二个问题是您的事件循环中间有一个“while(true)”,从而阻止了任何线程实际退出。

    while(thePartyIsOn){
        try { Thread.sleep(initialDelay); } 
        catch (InterruptedException e) { e.printStackTrace(); }
        log("Started dining with delay of " +initialDelay+ " miliseconds...");
        while(true){         // <<-- oops
            switch(state){

【讨论】:

  • 我什至没有尝试运行它。没有注意到错误的锁定逻辑。死锁线程可以解释这种行为。不错的收获。
  • 感谢您的评论伙伴,我发现了一些我不知道的事情,但我的哲学家被卡住并不奇怪。我故意没有在网上参考任何算法,我预计代码可能会在这里和那里失败。只是出于好奇......你说我的代码很复杂是什么意思?
  • 你的意思是我在 OP 之后的评论中?代码太复杂,无法用肉眼调试。
【解决方案2】:

我认为您的问题在正式开始TheDinner 中:

for(Philosopher p : phs){
    Thread t = new Thread(p);
    t.start();
}

您永远不会等待线程完成。一旦你的主程序退出,线程就会死掉,因为它们不是守护线程。您最好使用 ExecutorService 从固定大小的线程池中执行可运行对象。然后你可以shutdown()awaitTermination(...) 让线程完成它们的任务。

【讨论】:

  • 我给你一个“不”插入正确的地方。 (提示:在“死”之前)
  • 你说得对,它们工作了大约 5 秒,然后计时器唤醒睡着的家伙,然后让每个哲学家离开。谢谢。我将在代码中添加更多打印行,也许这会揭示问题。
猜你喜欢
  • 2020-05-05
  • 2018-06-02
  • 2016-03-04
  • 2022-12-29
  • 2015-10-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-09
相关资源
最近更新 更多