0

synchronizedJavaでブロックを実装する方法について、私はちょっと混乱しています。

状況の例を次に示します。

public class SlotWheel extends Thread implements ActionListener
{
  private int currentTick; // This instance variable is modified in two places

  private synchronized void resetCurrentTicks()
  {
    currentTick = 0;
  }

  private synchronized void incrementCurrentTicks()
  {
    ++currentTick;
  }

  public void actionPerformed(ActionEvent e)
  {
    resetCurrentTicks();
  }
}

プログラムの実行中に、ユーザーが を呼び出すボタンをクリックして、 を呼び出す可能性がありactionPerformedますresetCurrentTicks。同時に、実行中のスレッドはincrementCurrentTicks各ループ反復で呼び出しています。

私はまだ Java とプログラミングに慣れていないので、実装がcurrentTick破損から保護されているかどうかはわかりません。

私の実装は、実行中のスレッド内でincrementCurrentTicks呼び出された場合にのみ機能すると感じていますが、別のメソッドから操作しているため、私の実装は間違っています。actionPerformedcurrentTick

4

4 に答える 4

0

まず、Javaは、「スカラー」値(整数、文字、浮動小数点数など)がそれ自体でアトミックであることを保証します。そのため、このような値を同時に変更して2つのソースの混合を取得することはできません。2つの「同時」変更のいずれかの値を取得することが保証されています。x++ただし、 2つのスレッドが同時にインクリメントを試み、場合によっては1つのインクリメントのみが発生する可能性があるため、たとえば、から一貫性のない結果が得られるx可能性があります。(OTOH、同時に実行x = 7;する2つのスレッドは、明らかに互いに干渉しません。同時アクセスによって爆発などが発生することはありません。)

次に、synchronizedキーワードが2つのわずかに異なるコンテキスト(メソッド修飾子とブロック修飾子)で使用されていることを理解してください。2つの間にいくつかのささやかな違いがあります。

ブロック修飾子として使用する場合は、と言いsynchronized(object_ref) {some block}ます。この場合、synchronizedステートメントはによって識別されるオブジェクトのロックを取得し、同じオブジェクトを参照して同時に実行を試みる可能性のあるobject_ref他のすべてのステートメントは、現在のステートメントがそのブロックを終了する間、保留されます。syncronized

メソッド修飾子として使用する場合、関数は同じですが、非静的メソッドの場合、「this」オブジェクトがロックされ、メソッド全体がロックによって「保護」される点が異なります。

(一方、静的メソッドの場合、オブジェクトはロックされます。これは、同期ブロックClassと同等の、わずかに特殊なケースです。)synchronized(ClassName.class){some block}

synchronized2つのブロックまたはメソッドが同時に実行されないようにするには、それらが同期オブジェクトとして、単に同じクラスの1つではなく、同じオブジェクトを参照している必要があることを理解することが重要です。

于 2012-11-13T04:02:57.800 に答える
0

大丈夫そうです。

http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.htmlを参照してください。

同じオブジェクトに対する同期メソッドの 2 つの呼び出しをインターリーブすることはできません。

もちろん、GUI スレッドがティックをいじろうとしているかどうかを考慮する必要があります。単純なケースではおそらく問題ありませんが、より複雑なケースでは、「作業」を GUI スレッドからプッシュしたい場合があります。

于 2012-11-13T03:47:33.627 に答える
0

あなたの本能は正しいです。複数のメソッド間で一貫してクラス プロパティへのアクセスを同期することは困難です。そうしようとするのではなく、 java.util.concurrent.atomic.AtomicIntegerを確認することをお勧めします。大量のボイラープレート コードを記述およびテストすることなく、基になるプロパティへの安全な同時アクセスを提供します。

コードに組み込むと、次のようになります。

public class SlotWheel extends Thread implements ActionListener {
  private AtomicInteger currentTick = new AtomicInteger();

  private void resetCurrentTicks() {
    currentTick.set(0);
  }

  private void incrementCurrentTicks() {
    currentTick.incrementAndGet();
  }

  public void actionPerformed(ActionEvent e)
  {
    resetCurrentTicks();
  }
}
于 2012-11-13T03:51:00.970 に答える
-1

安全ではないという点で、あなたは正しいです。ただし、スコープ内の任意のオブジェクトで単純に同期し、メソッド定義から「同期済み」を削除することができます

public class MyThread {
  private Object lock = new Object();
  private int counter;

  protected void threadMetod() {
    synchronized (lock) {
      counter++;
    }
  }

  public void otherReset() {
    synchronized (lock) {
      counter = 0;
    }
  }
}
于 2012-11-13T03:53:07.340 に答える