哲学者の問題の解決

再発

public class Chopsticks {
    
    

}

哲学者

public class Philosopher  {
    
    

    public Philosopher(String name, Chopsticks left, Chopsticks right) {
    
    
        this.name = name;
        this.left = left;
        this.right = right;
    }

    private String name;
	// 左手筷子	
    private Chopsticks left;
	// 右手筷子
    private Chopsticks right;

    public void eating(){
    
    
        synchronized (left) {
    
    
            try {
    
    
                Thread.sleep(1000);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            synchronized (right) {
    
    
                try {
    
    
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
                System.out.println(this.name+" is eating ...");
            }
        }
    }
}

メイン機能

public class Main {
    
    
    public static void main(String[] args) {
    
    
        Chopsticks c1 = new Chopsticks();
        Chopsticks c2 = new Chopsticks();
        Chopsticks c3 = new Chopsticks();
        Chopsticks c4 = new Chopsticks();
        Chopsticks c5 = new Chopsticks();

        // 分配筷子
        Philosopher p1 = new Philosopher("p1",c1,c2);
        Philosopher p2 = new Philosopher("p2",c2,c3);
        Philosopher p3 = new Philosopher("p3",c3,c4);
        Philosopher p4 = new Philosopher("p4",c4,c5);
        Philosopher p5 = new Philosopher("p5",c5,c1);

        new Thread(()->{
    
    
            p1.eating();
        }).start();
        new Thread(()->{
    
    
            p2.eating();
        }).start();
        new Thread(()->{
    
    
            p3.eating();
        }).start();
        new Thread(()->{
    
    
            p4.eating();
        }).start();
        new Thread(()->{
    
    
            p5.eating();
        }).start();

    }
}

を使用する場合、最初に左手が割り当てられ、次に右手が割り当てられるため、デッドロックの問題が発生します。

jpsで表示

  1. 最初にプロセス番号を取得します
    ここに画像の説明を挿入します

  2. プロセス番号に従ってデッドロックのインストールステータスを表示する
    ここに画像の説明を挿入します

  3. デッドロックの詳細
    ここに画像の説明を挿入します

解決する

上記では、哲学者p1が最初に左側の箸c1を取得し、哲学者p5が最初に左側の箸c5を取得し、次に哲学者p1が右側の箸c5を取得しますが、この時点でc5は哲学者によって占有されています。 p5であり、奪うことはできないので、p1は待機しています。他の哲学者も同様であり、デッドロックを引き起こしました。

優先度によるリソースの割り当て

上記の例では、割り当てる場合、最初に左手で配布し、次に右手で配布します。割り当て方法を変更し、リソースを順番に割り当てることができます。上記の例では、p5リソースのみが順番に割り当てられていないため、次の変更を加えることができます。

ここに画像の説明を挿入します
操作結果を下図に示し、最後にp5を実行します。デッドロックの問題は、リソースの順次割り当てを使用するだけ解決できますが、p5は常に最後にリソースを取得するため、枯渇の問題が発生します。
ここに画像の説明を挿入します

リリースを待っています

上記の例では、順次割り当てによりデッドロックループ待機状態の発生を回避しています。この例では、不可侵の状態を回避し、デッドロックを回避することができます。哲学者が左手のリソースを取得したときに、右手のリソースを時間内に申請しなかった場合、彼は占有していたすべてのリソースを解放します。

箸のコードを変更して、reentrantlockを継承し、ロックして解放できるようにします。

public class Chopsticks  extends ReentrantLock {
    
    

}

哲学者

食べる方法のコードを変更しても、他のコードは変更されません。哲学者が左手を手に入れることができない場合、それは待ち続けます。哲学者が左手の箸を手に入れ、右手の箸を手に入れなかった場合、彼は左手の箸を放します。

public void eating(){
    
    
       while(true) {
    
    
           try {
    
    
               Thread.sleep(1000);
           } catch (InterruptedException e) {
    
    
               e.printStackTrace();
           }
           if (left.tryLock()) {
    
    
               try {
    
    
                   try {
    
    
                       Thread.sleep(1000);
                   } catch (InterruptedException e) {
    
    
                       e.printStackTrace();
                   }
                   if(right.tryLock()) {
    
    
                       try{
    
    
                           System.out.println(this.name+" is eating ...");
                           break;
                       }finally {
    
    
                           right.unlock();
                       }
                   }
               } finally {
    
    
                   left.unlock();
               }
           }
       }
   }

操作結果は以下のとおりです。p5は常に最後にあるとは限らないので、空腹の問題はありません。
ここに画像の説明を挿入します

おすすめ

転載: blog.csdn.net/qq_41948178/article/details/107813434