1

通知を受け取ったら、非同期で更新操作を行う必要があります。以下のupdate()メソッドは、インスタンス変数を操作します。

    public class UpdateOperation implements Runnable
    {
        private Boolean isInProgress = false;

        @Override
        public void run() {
            try 
            {
                synchronized (isInProgress)
                {
                    isInProgress = true;
                }
                update(); //perform update
                synchronized (isInProgress)
                {
                    isInProgress = false;
                }
            } 
            catch (UpdaterException e) 
            {
                    // deal with it                 
            }
        }

    }

// In another class
private UpdateOperation mCurrentUpdateOperation = new UpdateOperation(); 

public void updateRequired()
{
    synchronized (mCurrentUpdateOperation.isInProgress)
    {
        if (!mCurrentUpdateOperation.isInProgress)
        {
            new Thread(mCurrentUpdateOperation).start();
        }
        else
        {
            // reschedule or silently ignore                
        }
    }   
}

この設定は、2つの更新操作を同時に実行するのに十分ですか?ブロックに到達した最初のスレッドがsynchronizedロックを取得し、操作を開始し、ロックを解放するためだと思います。次に、2番目(またはそれ以上)がロックを取得し、操作が進行中であることを確認し、スケジュールを変更して、ロックを解放します。

このセットアップが失敗することはありますか?

4

3 に答える 3

3

この設定は、2つの更新操作を同時に実行するのに十分ですか?

いいえ、ロックしているオブジェクトのためです。常に非最終オブジェクトで同期する必要があり、では同期しないBooleanください。値がisInProgress変更されると(trueまたはに設定されているためfalse)、複数のスレッドが異なるオブジェクトをロックし、同時にミューテックスブロックに入ることができます。

UpdateOperation代わりに、インスタンスを作成できる場合は、インスタンスをロックすることができますfinal。あなたはいつでも次のようなことをすることができます:

 private final Object lockObject = new Object();
 ...
 synchronized (lockObject) {
     ...
 }

オブジェクトをロックするinProgressと、ブールプリミティブである可能性のあるの状態を確認できます。synchronizeコンストラクトはすべてのメモリを同期します。詳細については、同期に関するJavaスレッドのチュートリアルを参照してください。

BooleanJVM全体でそれらの定数オブジェクト参照が2つしかないため、をロックすることは特に悪いことです(そうしない限りnew Boolean(...))。あなたが言う時:

isInProgress = true;

あなたは事実上次のように言っています:

isInProgress = Boolean.TRUE;

したがって、すべてのクラスのすべてのスレッドが同じ2つのオブジェクトをロックし、奇妙な結果になります。

詳細については、ここで私の答えを参照してください:

ブール値で同期するのはなぜ良い習慣ではないのですか?

于 2013-01-23T19:14:59.107 に答える
1

Executorを見てください。それらはスレッドプールを提供し、あなたは単にあなたを実行可能に追加することができます。また、AtomicIntegerを使用することもできます。

これはあなたが望むすべてを提供し、使いやすいと思います。

于 2013-01-23T19:21:30.667 に答える
1

元のソリューションのもう1つの問題は、変数のチェックと設定がisInProgress異なる同期ステートメントにあるため、時間のギャップが生じることです。その結果、複数のスレッドが開始される可能性があります。

正しい解決策は次のとおりです。

public class UpdateOperation implements Runnable {
    private boolean inProgress = false;

    public void start() {
       synchronized (this) {
           if (inProgress) {
              return;
           }
           inProgress=true;
       }
       new Thread(this).start();
    }

    @Override
    public void run() {
        try  {
            update(); //perform update
        } catch (UpdaterException e) {
                // deal with it                 
        } finally {
            synchronized (this) {
                inProgress = false;
            }
        }
    }

}

// In another class
private UpdateOperation mCurrentUpdateOperation = new UpdateOperation(); 

public void updateRequired() {
      mCurrentUpdateOperation.start();
}
于 2013-01-24T05:04:00.060 に答える