2016-04-08 11 views
1

私はTimeBombオブジェクトを持っています。タイミングロジックに基づいて爆弾を爆発させなければならない。爆弾は最大10秒間待機し、その時間間隔では、その間隔の誰も爆弾を最新の時間にリセットしなければ爆発する。私は実装を思いついた。私はタイマーを現在の時間に16:24:40と言うように設定して待機ロジックを開始しています。今、爆弾はすべて16時24分50秒に爆発する予定です。 2秒間寝た後、爆弾を現在の時刻に16:24:42にリセットします。最大待機時間が10秒であるので、今度は爆弾が16:24:52に爆発するはずですが、私が実装したロジックは常に16:24:50に爆発します。どこが間違っているの?非アクティブの待機ロジック

public class TestTimeBomb { 

    public static void main(String[] args) throws InterruptedException { 
     TimeBomb bomb = new TimeBomb(); 
     long time1 = System.currentTimeMillis(); 
     System.out.println("First setting event at time " + getHumanReadableTime(time1)); 
     bomb.resetBomb(time1); 
     Job job = new Job(bomb); 
     new Thread(job).start(); 

     Thread.sleep(2000); 

     long time2 = System.currentTimeMillis(); 
     System.out.println("Second setting event at time " + getHumanReadableTime(time2)); 
     bomb.resetBomb(time2); 
    } 

    public static Date getHumanReadableTime(long time) { 
     Timestamp stamp = new Timestamp(time); 
     Date date = new Date(stamp.getTime()); 
     return date; 
    } 
} 

class Job implements Runnable { 

    TimeBomb bomb; 

    Job(TimeBomb bomb) { 
     this.bomb = bomb; 
    } 

    @Override 
    public void run() { 
     WaiterLogic waiterLogic = new WaiterLogic(bomb); 
     new Thread(waiterLogic).start(); 
    } 
} 

class WaiterLogic implements Runnable { 
    private TimeBomb test; 

    WaiterLogic(TimeBomb test) { 
     this.test = test; 
    } 

    @Override 
    public void run() { 

     long currentTimeMillis = System.currentTimeMillis(); 
     System.out.println("Entering while loop this job should end at " + TestTimeBomb.getHumanReadableTime(currentTimeMillis + 10000)); 
     while (true) { 
      long bombTime = test.getBombTime(); 
      long curentTime = System.currentTimeMillis(); 
      long diffTIme = curentTime - bombTime; 
      if (diffTIme > 10000) 
       break; 

     } 
     long end = System.currentTimeMillis(); 
     System.out.println("This job should have ended at" + TestTimeBomb.getHumanReadableTime(test.getBombTime() + 10000)); 
     System.out.println("But ended at time " + TestTimeBomb.getHumanReadableTime(end)); 
     System.out.println("Diff is " + (end - (test.getBombTime() + 10000))); 
    } 

} 

class TimeBomb { 

    private long bombTime; 

    public long getBombTime() { 
     return bombTime; 
    } 

    public void resetBomb(long bombTime) { 
     this.bombTime = bombTime; 
    } 
} 
+0

: – Sanjeev

+0

サンプル出力として働いていると思う –

+0

まず設定イベント時金4月で08午前17時29分11秒IST 2016 ループこのジョブは金4月で08午後5時29分21秒IST 2016 を終了する必要がありながら入力します2回目のイベントFri Apr 08 17:29:13 IST 2016 この仕事は4月8日17:29:23 IST 2016 で終了していたはずですが、4月8日17:29:21 IST 2016 Diff is - 2028 –

答えて

2

これは、bombTime変数がスレッドセーフではない並行性の問題であると想定しています。

1つのスレッド(main)では、値をbombTimeに設定し、別のスレッド(WaiterLogic)に値を設定しています。これらの2つのスレッドがこのデータを同時に取得しようとすると、各スレッドにキャッシュされたデータに矛盾が生じる可能性がある競合状態があります。

は、オプションのカップルは、この操作はスレッドセーフ


使用同期​​キーワードは、それがタスクを実行している間、スレッドがオブジェクトをロックさせるために使用されている

作ることがあります。​​がそうのようなTimeBombクラスメソッドで使用することで使用することができます。

class TimeBomb { 

    private long bombTime; 

    public synchronized long getBombTime() { 
     return bombTime; 
    } 

    public synchronized void resetBomb(long bombTime) { 
     this.bombTime = bombTime; 
    } 
} 

各メソッドに​​を追加することで、メインスレッドはWaiterLogicスレッドがgetBombTimeを呼び出している場合timebombオブジェクトにアクセスするために待機する必要があります。同様に、WaiterLogicスレッドは、メインスレッドがresetBombを呼び出している場合、timebombオブジェクトにアクセスするのを待機します。これにより、各スレッドが、bombTimeデータの正しいコピーをキャッシュすることが保証されます。


使用volatileキーワード

volatileキーワードは、それは、そのようなスレッドが値をキャッシュしないことになります。基本的には同期したブロックのように振る舞います。

private volatile long bombTime; 

Wikipediaがアトミックオブジェクトを記述するアトミックオブジェクトを使用:並行プログラミング、操作(または操作のセット)で

は、原子の線形化、不可分ですシステムの残りの部分が瞬時に発生するように見える場合は、中断しないでください。

javaでは、この目的でjava.util.concurrent.atomic.AtomicLongを使用できます。このオブジェクトには、volatileまたは​​のキーワードは必要ありません。それはすべてクラス自体によって処理されます。

class TimeBomb { 

    private AtomicLong atomicBombTime; 

    public long getBombTime() { 
     return atomicBombTime.get(); 
    } 

    public void resetBomb(long bombTime) { 
     atomicBombTime.set(bombTime); 
    } 
} 
0

wait(10000)とnotify(resetBombメソッド)を使用してループする代わりに、時間がかかりません。

私はそれが期待
関連する問題