

以下のようなメソッドを持った共有オブジェクトクラスを、Threadクラスを継承する方法やRunnableインターフェイスを実装する方法ではなく、Executorフレームワークを使って利用し、set()メソッドとreset()メソッドが交互に呼び出され出力するように実装してみたいです。

しかし、コードの書き方が悪いのか(おそらく)デッドロック状態になってしまい、うまくいきません。newFixedThreadPool(2)メソッドで、2つのメソッドを2つのスレッドがそれぞれ担当し、実行順序まで制御することは可能でしょうか？

もしクラス設計に問題がある場合は、クラスの作り方を変えても構いません。

[code]

    class Share {
         private int a = 0;
         private String b;
    
         public synchronized void set() {
              while(a != 0) {
                  try {
                       wait();
                  } catch(InterruptedException e) {
                     e.printStackTrace();
                  }
                  notify();
                  a++;
                  b = "data";
                  System.out.println("set() a : " + a + " b: " + b);
              }
         }
         public synchronized void reset() {
              while(b == null) {
                  try {
                       wait();
                  } catch(InterruptedException e) {
                     e.printStackTrace();
                  }
                  notify();
                  a--;
                  b = null;
                  System.out.println("reset() a : " + a +" b: " + b);
              }
         }
    }
    
[/code]

※以下、Threadクラスを継承したサブクラスを2つ作り、run()メソッドの中でそれぞれset()、reset()メソッドを呼び出すよう定義し、mainでstart()を呼び出すとうまくいきますが、Executorで単純な動作から学びたく質問させて頂きました。

何故かクラスとフィールド、クラスブロックが飛び出していてすいません。

※追記

[code]

    public static void main(String[] args) {
    
         ExecutorService service = null;
    
         try {
             service = Executors.newFixedThreadPool(2);
    
             Runnable task1 = () -> {
                  for(int i = 0; i < 5; i++) {
                       new Share().set();
                  }
             };
    
             Runnable task2 = () -> {
                  for(int i = 0; i < 5; i++) {
                       new Share().reset();
                  }
             };
             
             service.execute(task1);
             service.execute(task2);
    
             service.shutdown();
         }
    }
    
[/code]


CC BY-SA 4.0
2019-05-14T15:27:41.947
54952
2020-10-07T04:08:05.853
2020-09-05T04:52:45.333
3060
question
java
Executorフレームワークについて


行いたいことは大体こんな感じでしょうか。

[code]

    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class App {
    
        public static void main(final String[] args) {
            final Share share = new Share();
    
            final Runnable setter = new Runnable() {
                @Override
                public void run() {
                    share.set();
                }
            };
            final Runnable resetter = new Runnable() {
                @Override
                public void run() {
                    share.reset();
                }
            };
    
            final ExecutorService es = Executors.newFixedThreadPool(2);
            // 注: 厳密には、setメソッドの方がresetより先に呼ばれる保証は無い(はず)
            es.execute(setter);
            es.execute(resetter);
    
        }
    }
    
    class Share {
        private int a = 0;
        private String b;
    
        public synchronized void set() {
            System.out.println("called set");
            do {
                a++;
                b = "data";
                System.out.println("set() a : " + a + " b: " + b);
    
                notify();
    
                try {
                    wait();
                    System.out.println("setter waked");
                } catch (final InterruptedException e) {
                    e.printStackTrace();
                }
            } while (a == 0);
        }
    
        public synchronized void reset() {
            System.out.println("called reset");
            do {
                a--;
                b = null;
                System.out.println("reset() a : " + a + " b: " + b);
    
                notify();
    
                try {
                    wait();
                    System.out.println("resetter waked");
                } catch (final InterruptedException e) {
                    e.printStackTrace();
                }
            } while (b != null);
        }
    }
    
[/code]

* * *

> (おそらく)デッドロック状態になってしまい、うまくいきません。

書かれているコードについては、(どのように実行しているかにもよりますが、おそらく、)デッドロックになっているわけではなく、 `set` メソッドは
`a==0` なので `while` ループに入らず即座にリターンし、また、 `reset` メソッドは最初の `wait()`
で無限に待ち状態に入っています。

* * *

追記されている `main` メソッドの中では呼び出しごとに `new Share()`
が行われているので、`set`と`reset`で何の協調動作もなく単に並行に動作している状態です。  
どういう動作になることを想定されていますか？


CC BY-SA 4.0
2019-05-15T14:17:14.357
54985
2019-05-18T04:27:19.553
2019-05-18T04:27:19.553
2808
2808
54952
answer