私はスレッド化の経験があまりありませんが、Atomics を使用して気の利いたノンブロッキングのシーケンシャル ID ジェネレーターを作成しました.... テストのパフォーマンスが大幅に向上しました。なぜ同期が非常に遅いのになぜ誰もが使用するのだろうか...最新の64ビットマルチコアハードウェアに理由はありますか? 他の人は今、Atomics について私に尋ねています。古いハードウェアに展開する場合を除き、そのキーワードを決して使用しないように伝えたいと思います。
5 に答える
同期は非常に遅いため、なぜ誰もが同期を使用するのだろうか...
たぶん、スピードがすべてではないからです。
実際、実際のアプリケーションで「気の利いた」ジェネレーターを使用することによる全体的なパフォーマンスの利点を客観的に見ると、小さすぎて問題にならないことがわかると思います。アプリケーションをプロファイリングすると、それがわかります。
次に、ベンチマークが実際に有効かどうかという問題があります。つまり、JVM ウォームアップ異常や最適化異常などの誤解を招く影響を避けるために必要なことを行っているかどうかです。そして、(実際に)競合するケースと競合しないケースを測定しているかどうか。
Java Synchronized キーワードが Atomics よりも優れている実行可能なユース ケースはありますか?
簡単だ。
一連の操作、または本質的にスレッドセーフではない操作を実行するために、1 つ以上のデータ構造への排他的アクセスが必要な状況。タイプはこのAtomicXxx
種のものをサポートしていません。
古いハードウェアに展開する場合を除き、そのキーワードを決して使用しないように伝えたいと思います。
彼らにそれを言わないでください。正しくありません。実際、Java スレッドを初めて使用する場合は、アドバイスを始める前に、Goetz 氏らによる「Java Concurrency in Practice」を読むことをお勧めします。
アトミックのみを使用して複数のアクションを排他的に実行することはできないためです(技術的には、アトミックを使用して「ロック」を実装できるため、可能ですが、それは重要ではないと思います)。また、アトミックを使用してブロッキング待機を行うこともできません (ビジー待機を行うことはできますが、ほとんどの場合、それは悪い考えです)。
ここにOPの演習があります。複数のスレッドを使用してタイムスタンプ付きのログメッセージを同じファイルに書き込むプログラムを作成します。メッセージはタイムスタンプ順にファイルに表示される必要があります。アトミックのみを使用してこれを実装しますが、ReentrantLock/synchronized を再発明することはありません。
何をしているかによって異なります - アトミックが提供する機能のみが必要な場合は、はい、同じ作業を自分で行う必要はありません (synchronized キーワードを使用)。ただし、多くのマルチスレッド アプリケーションでは、アトミックに数値をインクリメントするだけでなく、はるかに複雑な処理を実行します。
たとえば、メモリ内のいくつかのデータ構造を変更する作業単位が必要な場合があり、そのすべてが干渉なしで発生する必要があります。そのために同期関数またはブロックを使用できます。
私の理解では、synchronized キーワードは、実際には適度に重い再帰 (再入可能) ロックです。
たとえば、次の (恐ろしい) コードはデッドロックしません。
public static Object lock = new Object();
int recurCount = 0;
public int fLocktorial(int n) {
synchronized(lock) {
recurCount++;
if (n <= 0)
return 1;
return n * fLocktorial(n-1);
}
}
これを実装するには、ロック内に追加の状態とロジックを維持する必要があり、アトミックやその他のプリミティブよりもパフォーマンスが低下する可能性があります。ただし、呼び出し元が既にロックを取得しているかどうかを心配することなく、関数内で任意にロックを取得できます。この場合、Atomics を使用して素朴に実装されたロックはデッドロックになります。
さらに、大量の処理がロック内で行われる場合、同期化によりパフォーマンスが向上する可能性があります。アトミックは操作ごとにコア同期を強制しますが、ロックを取得してもパフォーマンスは 1 回しかヒットしません。これにより、プロセッサ パイプラインがフラッシュされ、パフォーマンスに影響します。