javamultithreadingrunnabledining-philosopher

Dining philosophers - I spoke to all, just one listens


I'm implementing dining philosophers problem and I faced a problem myself, I do not know what's the cause, hence I am here.

It is after dinner when I'm telling them to leave, I want to force them to create reports cause that's the next stage of their lifetime. When I do so, all respond, but only one acts:

Console Output:

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



This is Philosopher class:

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 class:

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

Solution

  • I hacked up your code so it would run and then ran a debugger on it. You have two problems. The first is that you don't actually implement the Dinning Philosopher's algorithm. You just try to take the lock (Fork) without any checks or release algorithm. In my debugger at least two threads were stuck in tryEating(), both were stuck waiting for locks that would never be released.

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

    Those two variables, leftInHand and rightInHand are instance variables. They only check whether you have the lock. They don't check whether another philosopher has the lock.

    The second problem is that you have a "while(true)" in the middle of your event loop, preventing any thread from actually exiting.

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