2017-05-27 11 views
0

私はJavaアプリケーションを構築しており、プログラムの開始から何秒が経過したかを把握する必要があります。私はスレッドでこれを達成しようとしているので、私はtimeControllerスレッドを作成し、メインクラスを持って、5秒間待機してから、それを停止し、テスト目的のためにtimeControllerが今行うことになっていることを唯一のものは、経過秒を印刷します0.5秒ごとに。しかし、私の最終的な目標は、異なるオブジェクトの複数のスレッドに、同期方法で経過した秒数を問い合わせることです。今それが唯一の最初Calendar.SECONDを印刷し、決してその値を更新し、それが中断する前に5秒間実行され、半秒ごとに更新しているので、私は44 44 45 45 46 46 47 47 48 48のようなものを見ることが期待される(ときと仮定するためにシステム秒を開始した44)。ありがとうございました。今の秒を記録する方法は?

public class Main { 

    public static void main(String[] args) { 

     TimeController timeCon = TimeController.getInstance(); 

     timeCon.start(); 
     try { 
      Thread.sleep(5000); 
      timeCon.stop(); 
     } catch (Exception e){ 
      //ignore for now 
     } 
    } 
} 

public class TimeController implements Runnable{ 

    private static TimeController instance = null; 
    private volatile Thread timeCon; 

    private Calendar calendarInstance = Calendar.getInstance(); 
    private int secondsElapsed = 0; 
    private int incialSeconds = 0; 

    public int getElapsedSeconds(){ 
     return secondsElapsed; 
    } 

    public static TimeController getInstance(){ 
     if(instance == null){ 
      instance = new TimeController(); 
     } 
     return instance; 
    } 

    public void start(){ 
     timeCon = new Thread(this); 
     timeCon.start(); 
    } 

    public void stop(){ 
     timeCon = null; 
    } 

    @Override 
     public void run() { 
      Thread thisThread = Thread.currentThread(); 
      while (thisThread == timeCon) { 
       try { 
        Thread.sleep(500); 
        secondsElapsed = calendarInstance.get(Calendar.SECOND) - incialSeconds; 
        System.out.println(getElapsedSeconds()); 
       } catch (Exception e){ 
        //Ignore for now. 
       }    
      } 
     } 
} 
+1

一つであなたのクラスを置き換えることができます。 **そうすることが理にかなっている場合にのみ、マルチスレッドを使用してください**。つまり、1つのスレッドで実行できない場合です。それ以外の場合は、複雑さとバグを追加するだけです。 –

答えて

2

はそれだけで最初Calendar.SECONDを印刷し、決してあなたが、あなたのタイミングの問題への同時解決策を提供したいと思われ

その値を 更新しませんが、のどれもタイミングスレッドのコードが同期されます。このブロックは少なくとも疑わしいです:

private Calendar calendarInstance = Calendar.getInstance(); 
private int secondsElapsed = 0; 
private int incialSeconds = 0; 

public int getElapsedSeconds(){ 
    return secondsElapsed; 
} 

ここでは同期はありません。スレッドは異なるローカルキャッシュメモリを持つ異なるコア上で実行されている可能性があるため、あるスレッドの変数に対する変更が、別のプロセッサコアで実行されている別のスレッドから見えることは保証されません。それはおそらくあなたのコードで起こっていることです。

あなたは慎重に(ここでは、TimerController)あなたの変更可能なオブジェクトの状態空間を定義し、あなたのユースケースのために理にかなっているスレッドの安全性のポリシーを実装することをお勧めします。あなたのポリシーの目標は、あなたのオブジェクトの変更可能な状態を、生き生きと安全の失敗を引き起こす(すなわち、無効な状態遷移を防ぐ)競争状態から守ることです。これに対処する一般的な方法は、ロックを使用して相互排除と可視性を実現するためにモニターパターンを使用することです。

+0

返信いただきありがとうございます、私はマルチスレッド化に新しい、まだどのようにすべての作品を理解しようとしています。だから私の問題を解決するために何を提案しますか?それを同期させるにはどうすればいいですか? –

+0

私はあなたの要点を見ていますが、テスト目的のために、余分なメソッドを一切使用せず、すべてのコードを実行しても結果は同じです。 –

1

あなたはあなたのメインのコードと同じスレッドで、あなたが必要とするたびには、あなたがそれを必要とする瞬間でを経過時間を計算し、そしてあなたがそれを必要だけ必要があります。経過時間の値を常に計算して格納する別個のスレッドは必要ありません。

0

複数のスレッドがTimeControllerから時刻を取得しようとしたときに、今後この問題の特定のインスタンスに当てはまらない同期問題が発生する可能性があります。私は問題が、実際に実行メソッド内でCalendar.getInstance()を使用して各実行時に参照を更新する必要があるときに、私がCalendarへの静的参照を保持していることを知りました。ここではそれがどのように見えるべきかです:

@Override 
public void run() { 
    Thread thisThread = Thread.currentThread(); 
    while (thisThread == timeCon) { 
     try { 
      Thread.sleep(500); 
      secondsElapsed = Calendar.getInstance().get(Calendar.SECOND) - incialSeconds; 
     } catch (Exception e){ 
      //Ignore for now. 
     } 
    } 
} 
0

は、あなたもsimplier

public enum TimeController { 
    INSTANCE; 

    final long started = System.currentTimeMillis(); 

    public int getElapsedSeconds() { 
     return (System.currentTimeMillis() - started)/1000; 
    } 

    @Deprecated 
    public static TimeController getInstance() { 
     return INSTANCE; 
    } 
} 

またはマルチスレッドがあるについて学ぶためにキー物事の

public enum TimeController { 
    ; 

    static final long started = System.currentTimeMillis(); 

    public static int getElapsedSeconds() { 
     return (System.currentTimeMillis() - started)/1000; 
    } 
} 
関連する問題