web-dev-qa-db-ja.com

Javaで同期にコストがかかるのはなぜですか?

私はJavaに本当に慣れていないので、Javaではsynchronizedが「非常に高価」であると読みました。知りたいのは、何が高価で、どのように高価かということだけです。

ありがとう。

34
unj2

多分それはあなたが思うほど悪くはない

以前はひどいものでした(それが「非常に高価」だったと読んだ理由かもしれません)。これらのミームは消えるのに長い時間がかかることがあります

同期にはどのくらいの費用がかかりますか?

キャッシュのフラッシュと無効化を含むルールのため、Java言語の同期ブロックは、通常、アトミックな「テストアンドセット」で実装される多くのプラットフォームで提供されるクリティカルセクション機能よりも一般的に高価です。セットビット」マシン命令。プログラムに単一のプロセッサで実行される単一のスレッドのみが含まれている場合でも、同期されたメソッド呼び出しは、同期されていないメソッド呼び出しよりも低速です。同期で実際にロックの競合が必要な場合、パフォーマンスが低下します。いくつかのスレッドスイッチとシステム呼び出しが必要になるため、大幅に大きくなります。

幸い、JVMの継続的な改善により、全体的なJavaプログラムのパフォーマンスが向上し、各リリースとの同期の相対コストが削減され、将来の改善が見込まれます。さらに、同期のパフォーマンスコストはしばしば誇張されています。ある有名な情報源によると、同期されたメソッド呼び出しは、同期されていないメソッド呼び出しよりも50倍も遅いとのことです。このステートメントは正しいかもしれませんが、誤解を招く可能性があり、多くの開発者が同期を回避するようになっています。それが必要な場合。

そうは言っても、並行プログラミングはまだ遅い可能性がありますが、それは今では純粋にJavaのせいではありません。細かいロックと粗いロックの間にはトレードオフがあります。粗すぎるのは明らかに悪いことですが、ロックのコストはゼロではないため、細かすぎる可能性もあります。

競合している特定のリソースを検討することが重要です。メカニカルハードディスクは、スレッドが増えるとパフォーマンスが低下する例です。

37
John La Rooy

スレッドを使用していて、多数のスレッドがコードの同期されたセクションを通過する必要がある場合、一度に実行できるのはそのうちの1つだけであるため、コストがかかります。

それはボトルネックのようなものです。

シングルスレッドを使用する場合は、実行が許可されているかどうかをとにかくチェックする必要があるため、さらにコストがかかります。

同期されたセグメントの使用を減らすと、スレッドが実行できるかどうかを確認するためにスレッドを停止する必要がなくなります(もちろん、データを共有する必要はありません)。

同期がどのように機能するかの概要がわかります ここ

http://img20.imageshack.us/img20/2066/monitor28synchronizatioc.png

A Javaスタイルモニター

14
OscarRyz

これはJavaに固有のものではありません。同期は、正しく行われなかった場合、マルチスレッド環境では「高価」と見なされる可能性があります。 Javaで特に悪いのかどうかはわかりません。

スレッドが同じリソースを使用している場合、スレッドが同時に実行されるのを防ぎます。しかし、それらはdo同じリソースを使用するため、これ以上のオプションはありません(実行する必要があります)。

問題は、スコープが大きすぎるリソースを保護することがよくあることです。たとえば、不適切に設計されたプログラムは、配列内の個々の要素(または配列のセクション)ではなく、オブジェクトの配列全体を同期する場合があります。

これは、要素7を読み取ろうとするスレッドは、要素22の読み取りまたは書き込みスレッドを待機する必要があることを意味します。必須ではありません。同期の粒度が配列レベルではなく要素レベルである場合、これら2つのスレッドは互いに干渉しません。

2つのスレッドがsame要素にアクセスしようとした場合にのみ、リソースの競合が発生します。そのため、一般的なルールは、可能な限り小さなリソースのみを保護することです(もちろん、同期の数に制限があります)。

しかし、正直なところ、2つのスレッドが単一のリソースをめぐって争うことによるデータの破損が代替手段である場合、どれほど費用がかかるかは問題ではありません。アプリケーションを正しく記述し、パフォーマンスの問題が発生した場合にのみ心配します(「最初に動作させる次に高速に動作させる」が私のお気に入りのマントラです)。

7
paxdiablo

この 記事 IBMでの話は、実際には同期の背後にある主要なポイントを非常にうまく要約しています。

キャッシュのフラッシュと無効化を含むルールのため、Java言語の同期ブロックは、通常、アトミックな「テストアンドセット」で実装される多くのプラットフォームで提供されるクリティカルセクション機能よりも一般的に高価です。セットビット」マシン命令。プログラムに単一のプロセッサで実行される単一のスレッドのみが含まれている場合でも、同期されたメソッド呼び出しは、同期されていないメソッド呼び出しよりも低速です。同期で実際にロックの競合が必要な場合、パフォーマンスの低下は大幅に大きくなります、いくつかのスレッドスイッチとシステム呼び出しが必要になるため。

5

他の回答は、私が複製しようとはしない、かなりのレベルの技術的な詳細を提供します。

私がすることは、記事の日付(および著者の暗黙の能力と認識)を確認することをお勧めします。 Javawasの同期は、以前のJVMでは非常に低速でした。ただし、最近大幅に改善されたため、競合のない同期は思ったよりもはるかに高速で、競合のない同期も改善されました。

念のために言っておきますが、この質問はおそらく問題ではありません。正確性を確保するために同期する必要がある場合は、正確性を確保するために同期する必要があります。速度が問題になっていることがわかるのは、代わりにロックレス実装の作成を検討している場合(非常に効率的でありながら複雑な Java.util.concurrent.locks.AbstractQueuedSynchronizer を使用)、またはおそらく使用を検討している場合のみです。代わりに、タスク用の別の言語。

一般に、最良の結論は、同期は一般に最初の反復で使用するのに十分高速であるということだと思います。すべてのパフォーマンスの懸念と同様に、最初は明確さと正確さのためにコードを記述し、次に測定したものだけを最適化して、アプリケーションの高価な部分にします。通常、これは同期のコストにはなりません*。

3
Andrzej Doyle