2

monthArray複数のコンシューマーによって読み取られ、単一のperiodicallスケジュールされたアップデータースレッドによって定期的に更新されるデータ変数があります。すべて非同期。

更新を安全に実行するために、これらのオプションの両方を検討しました。

    ArrayList<String> tempArray = ModelJob.getDistinctMonths(user, true);       
    synchronized (monthArray) {
        monthArray = tempArray;
    }

また

    synchronized (monthArray) {
        monthArray = ModelJob.getDistinctMonths(user, true);
    }

最初のものの背後にある考え方は、ModelJob.getDistinctMonths(user, true);呼び出しに時間がかかり、同期を保持してブロックする必要がある時間より長くしたくないということです。更新された配列で古い配列をすばやく再割り当てするためだけです。しかし、あいまいなようで、完全に必要な場合にのみやりたいと思います。jvmがこの同期と天気をどのように処理するか、または前者を実行しないとパフォーマンスが向上するかについて、誰かが私に洞察を与えることができますか?基本的に、jvmが静的ModelJob呼び出し全体をブロックするかどうか、または再割り当てのブロックのみで回避できて安全かどうか、もしそうなら、そうするのに十分賢いかどうかを尋ねます。

4

5 に答える 5

3

呼び出しの周りで同期する必要がないと仮定するgetDistinctMonths()と(その呼び出しはスレッドセーフであり、呼び出しと割り当ての周りで原子性は必要ありません)、割り当ての周りで同期することができます(はい、ブロッキングは同期されたブロックにのみスコープされます。そうでない場合、構文は無意味になります)。@JohnVintは、monthArray参照が変更されているときに参照を同期してはならないという良い点を示していることに注意してください。変更されない別のオブジェクトインスタンスで同期する必要があります。

最後に、同期ブロックを削除してmonthArrayメンバーを揮発性にし、同じ結果を得ることができます。

于 2012-07-17T14:05:52.657 に答える
1

volatile修飾子を付けてmonthArrayすべてのブロックを削除するとsynchronized、ロックのないスレッドセーフが得られます。

また、JVMは、よりクリーンな(2番目の)バージョンのコードを最適化して、最初のバージョンであるかのように実行する場合があります。したがって、ロックを維持する場合は、よりクリーンなバージョンに固執することをお勧めします。

于 2012-07-17T14:17:05.743 に答える
1

最初のアプローチを使用する方が、パフォーマンスの観点から優れています。不要な同期を回避します。

覚えておかなければならないことの1つは、monthArrayの読み取りでさえ同期する必要があるということです。同期は、更新と読み取りの両方が同じオブジェクトロックを使用して同期されている場合にのみ機能します。オブジェクトロッククラスを使用したいと思います。たとえば、このコードがModelUpdateクラスの一部である場合は、次のコードを使用します

synchronized(ModelUpdate.class) {
        monthArray = tempArray;
}
于 2012-07-17T14:17:20.693 に答える
1

同期されたブロックは、実行全体を常にブロックします。パラメーターとして指定されたオブジェクト(この場合はmonthArray)は「モニター」と呼ばれ、パラメーターと同じオブジェクト(monthArray)を持つ他のすべての同期ブロックが非同期で実行されることを保証します。

于 2012-07-17T14:18:37.777 に答える
1

ここでの明らかな欠陥の1つは、変更されるオブジェクトを同期してはならないことです。

私は最初の例を好みますが、代わりに共通のロックを使用します

final Object lock = new Object();

synchronized(lock){
   monthArr = ...;
}

ただし、ほとんどの場合、monthArrvolatileを宣言すると同じ効果があります。

于 2012-07-17T14:19:35.903 に答える