web-dev-qa-db-ja.com

同期を使用する場合Java

これで十分な情報になるといいので、ここで説明します。あなたがより多くの情報を必要とするならば、lemmeはコメントで知っています。

2つの内部クラスを持つクラスがあります。内部クラスにはそれぞれ、外部クラスのメソッドを呼び出す2つのメソッドがあります。したがって、次のようになります。

public OuterClass {
    private boolean outerMethodHasBeenCalled = false;

    private void outerMethod() {
        if(!outerMethodHasBeenCalled) {
            // do stuff
        }

        outerMethodHasBeenCalled = true;
    }

    private FirstInnerClass {
        public void someMethod() {
            outerMethod();
        }
    }

    private SecondInnerClass {
        public void someOtherMethod() {
            outerMethod();
        }
    }
}

次の点に注意することが重要です。

  • これはAndroidアプリ用です。FirstInnerClassSecondInnerClassのインスタンスはJavaScriptインターフェースとしてWebViewに渡されるため、someMethodsomeOtherMethodは、特定の順序でいつでも呼び出すことができます。
  • 現在、既存のコード(synchronizedキーワードなし)に問題があり、outerMethodがほぼ同時に呼び出されます(ログメッセージを出力すると、1000分の1秒のタイムスタンプが付けられます) )さまざまなオブジェクトによって。 outerMethodHasBeenCalledが呼び出されたときにouterMethodがまだfalseであるため、私のアプリは '処理を2回行います'。これは大丈夫ではありません、そしてそれはまさに私が防ごうとしていることです。私のアプリは「何かをする」のは一度だけです。最初にouterMethodが呼び出されたときです。
  • OuterClassのインスタンスが複数あるように聞こえるかもしれませんが、OuterClassのインスタンスは1つだけですのでご安心ください。

outerMethodが最初に呼び出されたときだけ、私のアプリが「何かをする」ことが重要です(それが今では明らかであることを願っています)。以降のすべての呼び出しは基本的に無視されます。どちらの内部クラスが最初にouterMethodを呼び出すかは関係ありません。

それで、この場合、synchronizedキーワードを使用するのは適切ですか?

10
user5243421

うん、あなたが上にレイアウトしたものを考えると、私は一緒に行きます:

private synchronized void outerMethod() {
...
}

これには、outerMethod()が完了するまで呼び出し元の1つをブロックするという副作用があることに注意してください。それが許容できるなら、かっこいい。意図が単にouterMethod()のコードを一度実行することである場合、and最初の呼び出し元が遅れないように2番目の呼び出し元は問題ありませんがouterMethod()を実行している場合は、次のことを検討してください。

public OuterClass {
    private AtomicBoolean outerMethodHasBeenCalled = new AtomicBoolean();

    private void outerMethod() {
        if (outerMethodHasBeenCalled.compareAndSet(false, true)) {
            // do stuff
        }
    }
...

JavaDoc for AtomicBoolean を参照して、そこで何が起こっているかを調べてください(AndroidのJavaで利用可能であると想定しています)。

19
brettw

同期ブロックで1回だけ実行するすべてをouterMethodでラップします。

private void outerMethod() {
    synchronized (this) {
        if(!outerMethodHasBeenCalled) {
            // do stuff
        }

        outerMethodHasBeenCalled = true;
    }
}

そうすれば、メソッドが最初に呼び出されたときに、一度に1つのスレッドのみが同期ブロックに入ることができます。最初のものはifステートメントのコードを実行し、次にouterMethodHasBeenCalledtrueに設定します。他のスレッドはそれがtrueであることを確認し、ifコードをスキップします。

7
Brigham