-1

私は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()メソッドレビューしてください

4

2 に答える 2

1

あなたの直接の問題に対するassyliasの答えに加えて、ロジックを改善するためのいくつかの提案があります:

チェックleft.isBeingUsed()left.setChopStickUsed(true);他の誰かがすでに箸をつかんでいる可能性があります(これは、チェックの時間と使用の時間の問題と呼ばれます)。これが起こらないようにするには、適切なメカニズムを使用して、1 人の哲学者だけが箸オブジェクトにアクセスし、チェック+グラブをアトミックに実行できるようにする必要があります。たとえば、eat のロジックを次のように置き換えます。

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

whereChopstickには次のメソッドがあります。

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()、箸が使用されているかどうかを確認し、同時に使用されていない場合はそれつかむことです(これにより、チェック時間/使用時間の問題が回避されます)

: 上記の実装では、すべての哲学者が同時に左の箸をつかみ、使用中の右の箸を見つけ、左の箸を離し、考えて繰り返すライブロックが発生する可能性があります。したがって、決して食べません。これを解決するには、どのフォークを最初に取得するかを動的に (たとえばランダムに) 決定します。

于 2012-05-25T10:58:03.133 に答える
0

オブジェクトのロックを保持せずに入力したIllegalMonitorExceptionために取得します( )。javadocを確認する必要があります。waiteatthis

また、あなたは電話をかけnotifyないnotifyAllので、あなたは永遠に待つでしょう。

あなたは多分think代わりにそうするつもりでしたwaitか?

于 2012-05-25T09:59:26.563 に答える