2016-08-04 7 views
4

私はマルチスレッド化が初めてで、wait、notify、notifyAllの機能について知っています。私は3つのスレッドを1つずつ実行し、AからZまでのアルファベットを表示したい。 以下のコードを試してみたが、これもうまくいくようだが、これが問題を解決する最善の方法かどうかは疑問だ。それ以外の方法はありますか?私はそれをよりシンプルに、より良くすることができますか?私のコードの一部が繰り返されているようです。マルチスレッドプログラムを作成するにはどうすればいいですか?

package demo.threading; 

class Flags { 

    boolean flagA = true; 
    boolean flagB = false; 
    boolean flagC = false; 

} 

class Container { 

    Flags flags = new Flags(); 
    int charVal = (int) 'A'; 

    void producer1() { 

     try { 
      while (charVal <= (int) 'Z') { 
       synchronized (this) { 
        if (!flags.flagA) 
         wait(); 
        else { 
         System.out.println(Thread.currentThread().getName() + " Produced : " + (char) charVal); 
         flags.flagA = false; 
         flags.flagB = true; 
         charVal++; 
         notifyAll(); 
         Thread.sleep(1000); 
        } 
       } 
      } 
     } catch (InterruptedException ex) { 
      ex.printStackTrace(); 
     } 

    } 

    void producer2() { 

     try { 
      while (charVal <= (int) 'Z') { 
       synchronized (this) { 
        if (!flags.flagB) 
         wait(); 
        else { 
         System.out.println(Thread.currentThread().getName() + " Produced : " + (char) charVal); 
         flags.flagB = false; 
         flags.flagC = true; 
         charVal++; 
         notifyAll(); 
         Thread.sleep(1000); 
        } 
       } 
      } 
     } catch (InterruptedException ex) { 
      ex.printStackTrace(); 
     } 
    } 

    void producer3() { 

     try { 
      while (charVal <= (int) 'Z') { 
       synchronized (this) { 
        if (!flags.flagC) 
         wait(); 
        else { 
         System.out.println(Thread.currentThread().getName() + " Produced : " + (char) charVal); 
         flags.flagC = false; 
         flags.flagA = true; 
         charVal++; 
         notifyAll(); 
         Thread.sleep(1000); 
        } 
       } 
      } 
     } catch (InterruptedException ex) { 
      ex.printStackTrace(); 
     } 
    } 
} 

public class Main { 
    public static void main(String[] args) { 

     Container container = new Container(); 

     Thread t1 = new Thread(() -> container.producer1(), "Thread 1"); 
     Thread t2 = new Thread(() -> container.producer2(), "Thread 2"); 
     Thread t3 = new Thread(() -> container.producer3(), "Thread 3"); 

     t1.start(); 
     t2.start(); 
     t3.start(); 

    } 
} 

出力は次のようになります。

あなたは、この「次々に」やりたい場合は、前に指摘したように
Thread 1 Produced : A 
Thread 2 Produced : B 
Thread 3 Produced : C 
Thread 1 Produced : D 
Thread 2 Produced : E 
Thread 3 Produced : F 
+3

最良の方法は 'のSystem.out.println(" ABC ... XYZABCです。 ..XYZABC ... XYZ ")';またはあなたが達成しようとしている秩序を問わず。このような例からマルチスレッドを学習しようとするときの問題は、単にマルチスレッドを必要としないということです。 –

+0

この例は幾分意味がありません: 'wait'をループで使うべきです** - " 1つの引数バージョンと同様に、割り込みと擬似ウェイクアップが可能で、このメソッドは常にループで使用する必要があります " * [JavaDoc](https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#wait--)からcatchブロックはスレッドを終了させるだけで、誤った割り込み。 – Fildor

+0

@Fildor、こんにちは、あなたのフィードバックのおかげで、同じを達成するためのより良い賢明な方法をお勧めしますか? –

答えて

0
package demo.thread; 

public class ABCPuzzle { 

    private static class RunnableImpl implements Runnable { 

     private String nextThread; 
     private ExecServ execServ; 

     public RunnableImpl(ExecServ execServ, String nextThread) { 
      this.execServ = execServ; 
      this.nextThread = nextThread; 
     } 

     @Override 
     public void run() { 

      String threadName = Thread.currentThread().getName(); 

      synchronized (execServ) { 
       try { 
        while (true) { 
         if (execServ.key > 'Z') 
          break; 

         if (threadName.equals(execServ.current)) { 
          System.out.println(threadName + " consuming " + execServ.key); 
          Thread.sleep(1000); 
          execServ.key++; 
          execServ.current = nextThread; 
          execServ.notifyAll(); 
         } else 
          execServ.wait(); 
        } 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
     } 
    } 

    private static class ExecServ { 
     private String current, next; 
     private char key = 'A'; 
    } 

    public static void main(String[] args) { 

     ExecServ execServ = new ExecServ(); 
     execServ.current = "t1"; 

     Thread t1 = new Thread(new RunnableImpl(execServ, "t2"), "t1"); 
     Thread t2 = new Thread(new RunnableImpl(execServ, "t3"), "t2"); 
     Thread t3 = new Thread(new RunnableImpl(execServ, "t4"), "t3"); 
     Thread t4 = new Thread(new RunnableImpl(execServ, "t1"), "t4"); 

     t1.start(); 
     t2.start(); 
     t3.start(); 
     t4.start(); 

    } 
} 

出力:アルファベットを3回印刷する

t1 consuming A 
t2 consuming B 
t3 consuming C 
t4 consuming D 
t1 consuming E 
t2 consuming F 
t3 consuming G 
t4 consuming H 
t1 consuming I 
t2 consuming J 
4

、あなたは実際には複数のスレッドを必要としません。私はそれがJavaの低レベルの並行処理プリミティブなどと比較して、簡潔でシンプルなあなたの並行コードを維持するために大きな助けのJava 5以降で利用可能ですjava.util.concurrentを探索をお勧めします

int numberOfThreads = 3; 
Semaphore semaphore = new Semaphore(1); 

for (int i = 1; i <= numberOfThreads; i++) { 
    new Thread(() -> { 
     try { 
      semaphore.acquire(); 
      for (char c : "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray()) { 
       System.out.println(Thread.currentThread().getName() 
         + " produced: " + c + "."); 
      } 
     } catch (InterruptedException e) { 
      // NOP 
     } finally { 
      semaphore.release(); 
     } 
    }, "Thread " + i).start(); 
} 

:しかし、あなたはSemaphoreを使用することによって、これを達成することができますwaitnotifyとなります。あなたが本当にその話題に興味があるなら、Brian Goetz's "Java Concurrency in Practice"は必読です。

EDIT:

public class ConcurrentAlphabet { 

    private volatile Thread current; 

    public static void main(String[] args) { 
     new ConcurrentAlphabet().print(3, 
       "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray()); 
    } 

    public void print(int numberOfThreads, char[] alphabet) { 
     Thread[] threads = new Thread[numberOfThreads]; 

     for (int i = 1; i <= numberOfThreads; i++) { 
      int offset = i - 1; 
      threads[offset] = new Thread(() -> { 
       Thread me = Thread.currentThread(); 
       Thread next = threads[(offset + 1) % numberOfThreads]; 

       for (int index = offset; index < alphabet.length; index += numberOfThreads) { 
        synchronized (this) { 
         while (me != current) { 
          try { 
           wait(); 
          } catch (InterruptedException e) { /* NOP */ } 
         } 

         System.out.println(me.getName(); + " produced: " + alphabet[index] + "."); 
         current = next; 
         notifyAll(); 
        } 
       } 
      }, "Thread " + i); 
     } 

     current = threads[0]; 

     for (Thread t : threads) { 
      t.start(); 
     } 
    } 

} 
+0

こんにちは、あなたの返信のおかげで、私は期待された出力を追加しました:) –

+0

@ GoutamSingh:あなたは代わりの解決策を開いていますか、 'wait'と' notify'を使いたいですか? – beatngu13

+0

どんな解決策も良いでしょう@ beatngu13: –

関連する問題