2016-07-08 9 views
0

私はカウンタを増分し、カウンタを二乗し、操作を繰り返す前に500ミリ秒待つ必要がある練習をしています。 私は2つのスレッドクラスとsynchronized修飾子を使用することを余儀なくされています。 可能でしょうか?誰か助けてくれますか? これは私のコードです:同期を使用して複数のスレッドを持つオブジェクトへの順次アクセス

import static java.lang.Thread.sleep; 

public class Sync2Thread{ 

    private static Counter c; 

    static class Counter{ 
     private int count; 

     public synchronized int getCount() { 
      return count; 
     } 

     public synchronized void incrCount() { 
      count++; 
      System.out.println("+1 => counter= "+count); 
      try { 
       sleep(500); 
      } catch (InterruptedException ex) { 
      } 
     } 
    } 

    public static void main (String[] args){ 
     c = new Counter(); 

     Thread t = new Thread(new IncrCounter()); 
     t.start(); 
     Thread t2 = new Thread(new Square());   
     t2.start(); 
    } 

    /** 
     * Thread that increment the counter 
     */ 
    static class IncrCounter extends Thread { 

      public void run(){ 
      for(int i = 0; i < 7; i++) 
      { 
       System.out.println("Current Counter = "+c.getCount()); 
       c.incrCount(); 
      } 
     } 
    } 

     /** 
     * Thread that calculates the square 
     */ 
    static class Square extends Thread { 

     public void run(){ 
      for(int i = 0; i < 7; i++) 
      { 
       int x = c.getCount(); 
       System.out.println(x + " squared =>"+ x*x + "\n");  
       yield(); 
      } 
     } 
    } 

} 

私の結果はと似ています

Current Counter= 0 
+1 => counter= 1 
Current Counter= 1 
+1 => counter= 2 
1 squared =>1 
2 squared =>4 
2 squared =>4 
2 squared =>4 
2 squared =>4 
..... 

それがなければなりません:

Current Counter= 0 
+1 => counter= 1 
1 squared =>1 

Current Counter= 1 
+1 => counter= 2 
2 squared =>4 

Current Counter= 2 
+1 => 3 
3 squared =>9 

は私がメインだと思うそんなに

+0

こんにちは!あなたはインクリメントの前にロックを使い、平方の後にそれを解放することができます。 –

+1

'Thread.yield()'メソッドは、あなたが思うように思っていません。あなたのコードが単一のCPUマシン上の協調マルチタスク環境で実行されていたのですが、現代のデスクトップまたはラップトップシステム上で実行されている最新のOSでは、 'yield()は何もしないことを想像することです。 –

+0

チップ(解決策ではない):錠を持っている間は眠らないでください。 – bowmore

答えて

0

ユーザーDoubiは、(待って、それは方法でうまく動作しますが、言うように)と、 notify()。

import static java.lang.Thread.sleep; 

public class Sync2Thread{ 

private static Counter c; 

static class Counter{ 
    private int count; 

    public int getCount() { 
     return count; 
    } 

    public void incrCount() { 
     count++; 
     System.out.println("+1 => counter= "+count); 
    } 
} 

public static void main (String[] args){ 
    c = new Counter(); 

    Thread t = new Thread(new IncrCounter()); 
    t.start(); 
    Thread t2 = new Thread(new Square());   
    t2.start(); 
} 

/** 
    * Thread that increment the counter 
    */ 
static class IncrCounter extends Thread { 

     public void run(){ 
     for(int i = 0; i < 5; i++) 
     { 
      synchronized (c) { 

       try { 
        System.out.println("Thread1 - Current Counter = "+c.getCount()); 
        System.out.println("Thread1 - Waiting to get notified after squared"); 
        // This waits for the other thread perform exponentiation 
        c.wait(); 
       } catch (InterruptedException ex) { } 
       System.out.println("Thread1 - Waiter thread got notified, let's raise!"); 
       // As soon as the other thread has raised to a power, it increments the counter. 
       c.incrCount(); 
       c.notifyAll(); 
      } 
     } 
     System.out.println("Thread1 end___"); 
    } 
} 

    /** 
    * Thread that calculates the square 
    */ 
static class Square extends Thread { 

    public void run(){ 
     for(int i = 0; i < 5; i++) 
     { 
      synchronized (c) { 

       int x = c.getCount(); 
       System.out.println("Thread2 - "+ x + " squared =>"+ x*x);  
       try { 
        sleep(500); 
        System.out.println("Thread2 - Sqared done, send notify\n"); 
        c.notifyAll(); 
        c.wait(); 
       } catch (InterruptedException ex) { } 
      } 
     } 
     System.out.println("Thread2 end___"); 
    } 
} 

}

出力例:

Thread1 - Current Counter = 0 
Thread1 - Waiting to get notified after squared 
Thread2 - 0 squared =>0 
Thread2 - Sqared done, send notify 

Thread1 - Waiter thread got notified, let's raise! 
+1 => counter= 1 
Thread1 - Current Counter = 1 
Thread1 - Waiting to get notified after squared 
Thread2 - 1 squared =>1 
Thread2 - Sqared done, send notify 

Thread1 - Waiter thread got notified, let's raise! 
+1 => counter= 2 
Thread1 - Current Counter = 2 
Thread1 - Waiting to get notified after squared 
Thread2 - 2 squared =>4 
Thread2 - Sqared done, send notify 

Thread1 - Waiter thread got notified, let's raise! 
+1 => counter= 3 
Thread1 - Current Counter = 3 
Thread1 - Waiting to get notified after squared 
Thread2 - 3 squared =>9 
Thread2 - Sqared done, send notify 

Thread1 - Waiter thread got notified, let's raise! 
+1 => counter= 4 
Thread1 - Current Counter = 4 
Thread1 - Waiting to get notified after squared 
Thread2 - 4 squared =>16 
Thread2 - Sqared done, send notify 

Thread1 - Waiter thread got notified, let's raise! 
+1 => counter= 5 
Thread1 end___ 
Thread2 end___ 
0

に感謝問題はyield yield()にあります。 「ちょっと、私の仕事は終わりました。他のスレッドが欲しいと思ったら、今すぐ実行状態に進むことができます。」したがって、スレッドは実行可能状態になり、次にどのスレッドが実行可能状態にあり、実行状態になることができるかを調べます。 yield()の前の2行が他のスレッドが待っている500msよりも速い場合、正方形のスレッドは実行可能な状態の唯一のスレッドになります。それですぐに再び働くことになるでしょう。

解決策は、2つのスレッドがwait()およびnotify()を使用して待機するか、yieldの代わりにsleepを使用するかのいずれかです。

+0

Yield()は「私は仕事をした」とは言わない。 「私はまだできている仕事はたくさんありますが、もしあなたが私に休憩を与えたいなら、これは楽しい時です」 –

+0

さて、そうです。あなたは私が言ったことを言った;-) – Doubi

0

いくつかの提案:

synchronizaed方法を取り外し、int countの代わりにAtomicIntegerを使用しています。

原子的に更新される可能性のあるint値です。原子変数のプロパティの説明については、java.util.concurrent.atomicパッケージ仕様を参照してください。あなたはインクリメントし、正方形の同じスレッドで、またはこれら二つのスレッドのための2つの異なるカウンタインスタンスを使用しない限りのAtomicIntegerは、あなたは、現在のコードを使用して期待どおりの結果を達成することはできません

、そのようなアトミックインクリメントカウンタなどのアプリケーションで使用されています。

コード例:(まだによる別のスレッドでカウンターアクセスに副作用を持つ)

import static java.lang.Thread.sleep; 
import java.util.concurrent.atomic.AtomicInteger; 
public class Sync2Thread{ 
    private static Counter c; 
    static class Counter{ 
     private static AtomicInteger count = new AtomicInteger(0); 
     public int getCount() { 
      return count.get(); 
     } 
     public void incrCount() { 
      count.incrementAndGet(); 
      System.out.println("+1 => counter= "+getCount()); 
      try { 
       sleep(500); 
      } catch (InterruptedException ex) { 
      } 
     } 
    } 
    public static void main (String[] args){ 
     c = new Counter(); 
     Thread t = new Thread(new IncrCounter()); 
     t.start(); 
     Thread t2 = new Thread(new Square());   
     t2.start(); 
    } 

    /** 
     * Thread that increment the counter 
     */ 
    static class IncrCounter extends Thread { 
      public void run(){ 
      for(int i = 0; i < 7; i++) 
      { 
       System.out.println("Current Counter = "+c.getCount()); 
       c.incrCount(); 
      } 
     } 
    } 
     /** 
     * Thread that calculates the square 
     */ 
    static class Square extends Thread { 
     public void run(){ 
      for(int i = 0; i < 7; i++) 
      { 
       int x = c.getCount(); 
       System.out.println(x + " squared =>"+ x*x + "\n"); 
       c.incrCount(); 

      } 
     } 
    } 
} 

出力:

Current Counter = 0 
0 squared =>0 

+1 => counter= 1 
+1 => counter= 2 
Current Counter = 2 
+1 => counter= 3 
3 squared =>9 

+1 => counter= 4 
Current Counter = 4 
+1 => counter= 5 
5 squared =>25 

+1 => counter= 6 
Current Counter = 6 
6 squared =>36 

+1 => counter= 7 
+1 => counter= 8 
8 squared =>64 

Current Counter = 8 
+1 => counter= 9 
+1 => counter= 10 
10 squared =>100 

+1 => counter= 11 
Current Counter = 10 
+1 => counter= 12 
Current Counter = 12 
+1 => counter= 13 
13 squared =>169 

+1 => counter= 14 
+0

質問は彼が同期を使用することを強制されていると言います(恐らく彼らが学んでいるものなので) – bowmore

+0

OPの問題は、かなり一般的なイントロスレッドの運動のバリエーションです。生徒は2つのスレッドを交互に行う方法を理解しているはずです。より一般的な形式では、すべての整数を1からNまで昇順に出力し、一方のスレッドはすべての奇数を生成し、他方は偶数のすべてを生成します。 IMO、これは悪い例です。なぜなら、生徒はスレッドをトリックにするために_how_について何かを学ぶかもしれないからです。スレッドを使用することについて完全に間違った考えを与えています。 –

+0

はい。出力に副作用を与えました。 –

関連する問題