Столовые философы - я говорил со всеми, только один слушает

Я внедряю проблему столовых философов, и я сам столкнулся с проблемой, я не знаю, в чем причина, поэтому я здесь.

После обеда, когда я говорю им уйти, я хочу заставить их создавать отчеты, потому что это следующий этап их жизни. Когда я так поступаю, все отвечают, но действует только одно:

Консольный вывод:

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



Столовая класса:

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

2 ответа

Я взломал ваш код, чтобы он запустился, а затем запустил на нем отладчик. У тебя две проблемы. Во-первых, вы фактически не реализуете алгоритм Dinning Philosopher. Вы просто пытаетесь взять блокировку (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; }      
}

Эти две переменные, leftInHand а также rightInHand являются переменными экземпляра. Они только проверяют, есть ли у вас замок. Они не проверяют, есть ли у другого философа замок.

Вторая проблема заключается в том, что у вас есть "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){

Я думаю, что ваша проблема здесь официально в StartTheDinner:

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

Ты никогда не ждешь окончания своих тем. Как только ваша основная программа завершит работу, потоки умрут, потому что они не являются потоками демонов. Возможно, вам лучше использовать ExecutorService для выполнения runnables из пула потоков фиксированного размера. Тогда ты можешь shutdown() а также awaitTermination(...) чтобы позволить потокам выполнять свои задачи.

Другие вопросы по тегам