2017-05-07 14 views
1

セマフォーとマルチスレッドの使用について一般的には勉強していますが、スタックしています。私はそれぞれGとHを印刷する2つのスレッドを持っています、そして、私の目的は、出力文字列がこのようになるように各スレッドの出力を交互にすることです。セマフォーを使用して2つのスレッドから代替出力を出力する

G 
H 
G 
H 
G 
H 

二つのクラスのそれぞれについて、以下

public class ClassA extends Thread implements Runnable{ 

    Semaphore semaphore = null; 
    public ClassA(Semaphore semaphore){ 

     this.semaphore = semaphore; 
    } 

    public void run() { 

     while(true) 
     { 
      try{ 
       semaphore.acquire(); 
       for(int i=0; i<1000; i++){ 
        System.out.println("F"); 

       } 
       Thread.currentThread(); 
       Thread.sleep(100); 
      }catch(Exception e) 
      { 
       System.out.println(e.toString()); 
      } 
      semaphore.release(); 
     } 

    } 

} 

以下のようなレイアウトは、私が取得しています出力は私からあまりにも異なっている

public static void main(String[] args) throws InterruptedException { 

    Semaphore semaphore = new Semaphore(1); 

    ClassA clasA = new ClassA(semaphore); 
    Thread t1 = new Thread(clasA); 
    ClassB clasB = new ClassB(semaphore); 
    Thread t2 = new Thread(clasB); 
    t1.start(); 
    t2.join(); 
    t2.start(); 

私のメインクラスですました期待される結果。誰でも私を助けてくれる?私はセマフォを誤用しましたか?どんな助け?

+0

あなたが本来のロックまたはリエントラントロックやセマフォまたは何を使用する場合、あなたが期待される順序を得るために、フォワードパスを提案してくださいだろうか、ただのロックを使用して[OK]を任意の順番 –

+0

を強制しません、問題ではありませんか。上記のコードの弱点は何ですか? – Jazztheman

答えて

0

セマフォは、このようなタスクを解決するのに役立ちません。

私が知る限り、JVMはスレッドの実行において何らかの命令を約束しません。つまり、複数のスレッドを実行すると、1つのスレッドが複数回連続して実行され、他のスレッドよりも多くのプロセッサ時間を持つことができます。したがって、スレッドを特定の順序で実行させたい場合は、最も単純な例として、スレッドのスイッチャーの役割を果たす静的ブール変数を作成します。 wait()とnotify()メソッドを使用する方が良い方法です。Interface Conditionが私が推測する最良の方法です。

import java.io.IOException; 

public class Solution { 
    public static boolean order; 

    public static void main(String[] args) throws IOException, InterruptedException { 
     Thread t1 = new ThreadPrint("G", true); 
     Thread t2 = new ThreadPrint("O", false); 
     t1.start(); 
     t2.start(); 
     t2.join(); 

     System.out.println("Finish"); 
    } 

} 

class ThreadPrint extends Thread { 

    private String line; 
    private boolean order; 

    public ThreadPrint(String line, boolean order) { 
     this.line = line; 
     this.order = order; 
    } 

    @Override 
    public void run() { 
     int z = 0; 
     while (true) { 
      try { 
       for (int i = 0; i < 10; i++) { 
        if (order == Solution.order) { 
         System.out.print(line + " "); 
         Solution.order = !order; 
        } 
       } 
       sleep(100); 
      } catch (Exception e) { 
       System.out.println(e.toString()); 
      } 
     } 
    } 
} 

ところで、System.outは通常、オペレーションシステムのバッファであり、あなたのOSは独自の順序でメッセージを出力できます。

P.S.スレッドを継承してRunnableを同時に実装しないでください。

public class ClassA extends Thread implements Runnable{ 

スレッドクラスはすでにRunnableを実装しているためです。あなたの目的に適した方法は1つだけ選択できます。

スレッドを開始してからスレッドに参加する必要があります。他の人のよう

t1.start(); 
t2.join(); 
t2.start(); 
0

指摘している、任意の順序を強制していないとThread.start()を呼び出すときに、スレッドを開始する(その上に、あなたが特定することができない自分自身をロックし、将来のある時点でスレッドを開始するが、これます時間がかかるかもしれない)。

しかし、ロックを使用して(Semaphoreなど)注文を実行できます。この場合、2つのセマフォを使用してスレッドのオンとオフを切り替えることができます(代替)。 2つのスレッド(またはRunnables)は事前に相互に認識しておく必要があります。つまり、スレッドがパーティに参加できるより動的なアプローチはより複雑になります。

繰り返し可能な結果を​​持つ実行可能なサンプルクラス以下(マルチスレッドのテスト時には常に良いことです)。それがなぜ、どのように働くかを理解するために、私はあなたに任せておきます。

import java.util.concurrent.*; 

public class AlternateSem implements Runnable { 

    static final CountDownLatch DONE_LATCH = new CountDownLatch(2); 
    static final int TIMEOUT_MS = 1000; 
    static final int MAX_LOOPS = 10; 

    public static void main(String[] args) { 

     ExecutorService executor = Executors.newCachedThreadPool(); 
     try { 
      AlternateSem as1 = new AlternateSem(false); 
      AlternateSem as2 = new AlternateSem(true); 
      as1.setAlternate(as2); 
      as2.setAlternate(as1); 
      executor.execute(as1); 
      executor.execute(as2); 
      if (DONE_LATCH.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 
       System.out.println(); 
       System.out.println("Done"); 
      } else { 
       System.out.println("Timeout"); 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } finally { 
      executor.shutdownNow(); 
     } 
    } 

    final Semaphore sem = new Semaphore(0); 
    final boolean odd; 
    AlternateSem other; 

    public AlternateSem(boolean odd) { 
     this.odd = odd; 
    } 

    void setAlternate(AlternateSem other) { this.other = other; } 
    void release() { sem.release(); } 
    void acquire() throws Exception { sem.acquire(); } 

    @Override 
    public void run() { 

     if (odd) { 
      other.release(); 
     } 
     int i = 0; 
     try { 
      while (i < MAX_LOOPS) { 
       i++; 
       other.acquire(); 
       System.out.print(odd ? "G " : "H "); 
       release(); 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     DONE_LATCH.countDown(); 
    } 
} 
関連する問題