Столовая философская задача. Помещение моей концепции в код

Я довольно новичок в потоках Java. Попытка сделать механизм взаимоблокировки с использованием концепций синхронизации Java. В этом есть некоторые проблемы. Я хочу знать, как я должен улучшить свой код. Моя цель - избежать тупика.

package threading;

import java.util.logging.Level;
import java.util.logging.Logger;


public class DiningPhilospherProblem {

  public static void main(String[] args)
  {
      Chopstick cs[] = new Chopstick [5];
      for(int i=0;i<5;i++)
      {
          cs[i] = new Chopstick();
      }


      new Thread(new Philospher("One", cs[4],cs[0]) ).start();
      new Thread(new Philospher("Two", cs[0],cs[1]) ).start();
      new Thread(new Philospher("Three", cs[1],cs[2]) ).start();
      new Thread(new Philospher("Four", cs[2],cs[3]) ).start();
      new Thread(new Philospher("Five", cs[3],cs[4]) ).start();
  }
}

class Philospher implements Runnable
{
    private static final int EATING_TIME = 8000;
    private static final int THINKING_TIME  = 10000;


    public enum State {
        EATING, THINKING, WAITING
    }

    Chopstick left, right;
    String name;
    State state;
    public Philospher(String name, Chopstick left,Chopstick right)
    {
        System.out.println(" Philospher "  + name + " is ready");
        this.name = name;
        this.left =left;
        this.right = right;
    }
    public void run()
    {
       for(int i =0; i< 10;i++){

                eat();

        }

        System.out.println("Succesfully finished: " +name);
    }
    public void eat()  // EDITED THIS FUNCTION
    {
        synchronized(left){
        try{


                while(right.isBeingUsed()){
                    System.out.println("Philospher " + name + " :  is waiting");
                    setPhilosopherState(Philospher.State.WAITING);
                    left.wait();
                }

                synchronized(right)
                {
                    left.setChopStickUsed(true);
                    right.setChopStickUsed(true);

                    System.out.println("Philospher " + name + " :  is eaitng");
                    setPhilosopherState(Philospher.State.EATING);

                    Thread.sleep(EATING_TIME);
                }
            }

        catch(InterruptedException e){}
        finally
        {
            left.setChopStickUsed(false);
            right.setChopStickUsed(false);
            left.notify();

        }
        }
        think();

    }

    public void think()
    {
        System.out.println("Philospher " + name + " :  is thinking");
        try 
        {
            setPhilosopherState(State.THINKING);
            Thread.sleep(THINKING_TIME);
        } 
        catch (InterruptedException ex) {
            Logger.getLogger(Philospher.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
     private void setPhilosopherState(State state){
        this.state = state;

        System.out.println("Setting state :  "+ state +", "+ name+";");
    }
}

class Chopstick
{
    boolean state_chopstick;

    public synchronized void  setChopStickUsed(boolean value)
    {
        state_chopstick = value;

    }
    public synchronized boolean isBeingUsed ()
    {
        return state_chopstick;
    }
}

Отредактировано: eat() метод Пожалуйста, просмотрите

2 ответа

Помимо ответа Ассилии на вашу прямую проблему, вот несколько предложений по улучшению логики:

Между проверкой left.isBeingUsed() а также left.setChopStickUsed(true); кто-то другой, возможно, уже схватил палочку для еды (это называется проблемой времени проверки и времени использования). Чтобы этого не произошло, вам нужно использовать соответствующий механизм, чтобы позволить только одному философу получить доступ к объекту палочки и выполнить check + grab atomicalliy, например, заменить логику еды на

boolean isEating = false;
if (left.grab()) {
  if (right grab) {
    // managed to grab both chopsticks
    isEating = true;
  } else {
    // only grabbed the left one
    left.release();
  }
} else {
  // could not grab the left one
}

if (isEating) {
  // TODO: chew, swallow
  left.release();
  right.release();
} else {
  // contemplate the cruelty of life
  think();
}

где Chopstick имеет следующие методы:

public synchronized boolean grab()
{
  if (state_chopstick) {
    // already in use
    return false;
  }
  _state_chopstick = true;
  return true; // managed to grab it
}

public synchronized void release()
{
  state_chopstick = false;
}

Идея в том, что grab() проверяет, используется ли палочка для еды, и захватывает ее, если она не одновременно (это позволяет избежать проблемы времени проверки / времени использования)

Примечание: приведенная выше реализация может привести к блокировке в режиме реального времени, когда все философы одновременно берут левую палочку, а затем находят правую, используют левую, думают и повторяют; таким образом, никогда не есть. Чтобы решить эту проблему, вы могли бы динамически (например, случайным образом) решить, какой форк получить первым

Вы получаете IllegalMonitorException потому что ты wait в eat не удерживая замок на объекте (this). Вы должны взглянуть на Javadoc.

Также ты не звонишь notify или же notifyAll так что будешь ждать вечно.

Вы, возможно, хотели think вместо wait?

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