web-dev-qa-db-ja.com

javaでデッドロックを防ぐためのヒント

私は勉強していますJavaスレッドとデッドロック、デッドロックの例を理解していますが、それを防ぐために従うべき一般的なルールがあるのだろうか。

私の質問は、デッドロックを防ぐためにJavaのソースコードに適用できるルールまたはヒントがあるかどうかです。はいの場合、実装方法を説明できますか?

44
iberck

私の頭からいくつかの簡単なヒント

  • 複数のスレッドを使用しないでください(たとえば、Swingのように、すべてがEDTで行われることを義務付けることによって)。
  • 一度に複数のロックを保持しないでください。その場合は、常に同じ順序でロックを取得してください
  • ロックを保持している間に外部コードを実行しないでください
  • 割り込み可能なロックを使用する
32
JB Nizet

カプセル化、カプセル化、カプセル化!ロックで最も危険な間違いは、ロックを世界に公開することです(公開すること)。オブジェクトを知らなくても誰でもロックを取得できるため、これを行うと何が起こるかわかりません(これは、thisをロックしない理由でもあります)。ロックをプライベートにすると、完全に制御でき、管理しやすくなります。

15
Despertar
  1. ロックのないデータ構造を使用してロックを回避します(たとえば、同期されたConcurrentLinkedQueueの代わりにArrayListを使用します)
  2. 常に同じ順序でロックを取得します。各ロックに一意の数値を割り当て、より高い数値のロックを取得する前に、より低い数値のロックを取得する
  3. タイムアウト期間後にロックを解除します(技術的には、これはデッドロックを防止するものではなく、発生したロックを解決するのに役立ちます)
12

読み、理解してくださいJava:Concurrency and Practice。これは、デッドロックを回避するための「ヒント」ではありません。デッドロックを回避するためのいくつかのヒントを知っていて、しばしばデッドロックを回避する開発者を雇うことは決してありません。並行性を理解することです。幸いなことに、このトピックに関する包括的な中級レベルの本があるので、読んでみてください。

10
djechlin
  1. ロックを使用しないでください。
  2. 必要な場合は、ロックをローカルに保持してください。グローバルロックは非常に注意が必要です。
  3. ロックを保持するときは、できるだけ実行しないでください。
  4. stripes を使用して、データのセグメントのみをロックします
  5. 不変型を優先します。多くの場合、これはデータを共有する代わりにデータをコピーすることを意味します。
  6. 代わりに、比較および設定(CAS)メカニズムを使用してください。たとえば、 AtomicReference を参照してください。
8
jontejj

設計上の選択肢が与えられた場合、キューのプッシュ/ポップにロックのみがある場所でメッセージの受け渡しを使用します。これは常に可能とは限りませんが、可能であれば、デッドロックはほとんどありません。あなたはまだそれらを手に入れることができますが、本当に一生懸命努力する必要があります:)

5
Martin James

デッドロックの防止に関しては、1つの大きなルールがあります。

コードに複数のロックを設定する必要がある場合は、全員が常に同じ順序でロックを取得するようにしてください。

ただし、コードをロックから解放することは、ほとんど常に目標です。不変オブジェクトまたはスレッドローカルオブジェクトとロックフリーのデータ構造を使用して、それらを取り除くことができます。

4
Keppil

これは、デッドロックの典型的な例です。

public void methodA()
{
  //...

  synchronized(lockA)
  {
     //...
     synchronized(lockB)
     {
      //...
     }
   }
}


public void methodB()
{
  //...

  synchronized(lockB)
  {
     //...
     synchronized(lockA)
     {
      //...
     }
   }
}

このメソッドは、多くのスレッドから呼び出された場合、おそらく大きなデッドロックを作成します。これは、オブジェクトが異なる順序でロックされているためです。これは、デッドロックの最も一般的な理由の1つです。したがって、それらを回避する場合は、ロックが順番に取得されるであることを確認してください。

4
aran

Javaのデッドロックは、2つ以上のスレッドが永久にブロックされるプログラミング状況です。Java少なくとも2つのスレッドと2つ以上のリソースでデッドロック状況が発生します。

Javaでデッドロックを検出する方法

Javaでデッドロックを検出するには、アプリケーションのJavaスレッドダンプを調べる必要があります。VisualVMプロファイラーまたはjstackユーティリティを使用。

デッドロックを分析するには、状態が[〜#〜] blocked [〜#〜]のスレッドと、それが存在するリソースを探す必要があります。ロックを待っています。すべてのリソースには一意のIDがあり、これを使用して、オブジェクトのロックをすでに保持しているスレッドを見つけることができます。

Javaでデッドロックを回避する方法

これらは、ほとんどのデッドロック状態を回避できるガイドラインの一部です。

  • 循環待機条件を解除してデッドロックを回避する:そのためには、ロックの取得と解放に順序を課すようにコード内で調整することができます。ロックが一貫した順序で取得され、逆の順序で解放される場合、1つのスレッドが他のスレッドによって取得されたロックを保持しているという状況はありません。
  • ネストされたロックの回避:これは、デッドロックの最も一般的な理由です。すでに保持している場合は、別のリソースのロックを避けてください。 1つのオブジェクトロックのみで作業している場合、デッドロック状態になることはほとんど不可能です。
  • 必要なもののみをロック:作業する必要があるリソースでのみロックを取得する必要があります。そのフィールドの1つだけに関心がある場合は、それだけをロックする必要があります特定のフィールドが完全なオブジェクトではありません
  • 無期限に待機しない:スレッド結合を使用して、2つのスレッドが相互に無期限に終了するのを待機している場合、デッドロックを取得できます。スレッドが別のスレッドの終了を待たなければならない場合は、常に、スレッドの終了を待つ最大時間でjoinを使用するのが最善です。
2
amitkumar12788
  • ネストされたロックを回避する
  • 不要なロックを回避する
  • スレッドjoin()を使用
1
Arun Raaj
  1. ネストされたロックを避けます。これがデッドロックの最も一般的な理由です。別のリソースを既に保持している場合は、ロックしないでください。1つのオブジェクトロックのみで作業している場合、デッドロックを取得することはほとんど不可能です。

  2. 必要なものだけをロックします。オブジェクト全体をロックするのではなく、オブジェクトの特定のフィールドをロックするように、目的にかなう場合。

  3. 無期限に待たないでください。

1
027
  1. 必要な場合を除き、複数のスレッドでデータを共有しないでください。作成/初期化後にデータを変更できない場合は、最終変数に固執します。
  2. 複数のスレッド間で共有データを回避できない場合は、粒度の細かいsynchronizedブロックまたは Lock sを使用します。
  3. synchronizedコードブロックのみを使用している場合、ロックが特定の順序で取得/解放されていることを確認してください。
  4. 他の代替手段を探してください:volatileまたは AtomicXXX 変数またはLock AP​​I

関連するSEの質問:

Javaでsynchronized(this)を避けますか?

Javaでのvolatileとsynchronizedの違い

揮発性ブール値vs AtomicBoolean

1
Ravindra babu