2

機能で 2 つのオブジェクトをロックする必要があり、現在のコードは次のようになります。

Object obj1  = ...//get from somewhere
Object obj2 = ...//get from somewhere

synchronized(obj1){
  ...//blah
  synchronized(obj2){
     ...//blah
  }
}

ご覧のとおり、これは、別のスレッドがこのコードを obj1 と 2 を逆にして実行した場合のデッドロックの単純明快なレシピです。
concurrency-utils ロックを使用してこの状況を回避する方法はありますか?

オブジェクトとそのロックのマップを維持し、それらが利用可能かどうかを確認することを考えていましたが、ロックの順序を予測する明確な方法を思いつくことができないようです.

4

5 に答える 5

7

ロックの順序は保持されますが、obj1 が obj2 に切り替えられると、デッドロックが発生します。

このケースを回避するには、別の解決策を探す必要があります: ロック順序 + オプションのタイ ブレーク ロック

int fromHash = System.identityHashCode(obj1);
int toHash = System.identityHashCode(obj2);

if (fromHash < toHash) {
    synchronized (obj1) {
        synchronized (obj2) {
               ........
        }
    }
} else if (fromHash > toHash) {
    synchronized (obj2) {
        synchronized (obj1) {
            ........
        }
    }
} else {
    synchronized (TIE_LOCK) {
        synchronized (fromAcct) {
            synchronized (toAcct) {
               ...
            }
        }
    }
于 2011-03-01T07:42:04.520 に答える
4

何をしているかによっては、最初にロックされたオブジェクトから必要なものを取得し、その情報を使用して 2 番目のロックされたオブジェクトを処理できる場合があります。例えば

それ以外の

synchronized(list1) {
  for(String s : list1) {
     synchronized(list2) {
       // do something with both lists.
     }
  }
}

これを行う

List<String> listCopy;
synchronized(list1) {
  listCopy = new ArrayList<String>(list1);
}

synchornized(list2) {
   // do something with liastCopy and list2
}

デッドロックが発生しないように、一度にしかロックできないことがわかります。

于 2011-03-01T09:01:44.607 に答える
3

obj1、次に obj2 の順序で一貫してロックする必要があります。この順序に違反しない場合、デッドロックは発生しません。

于 2011-03-01T06:37:25.853 に答える
1

本質的にあなたが持っているのは、食事の哲学者の問題です.

https://en.wikipedia.org/wiki/Dining_philosophers_problem

Ovidiu Lupas の答えは Dijkstra の Resource Heirarchy ソリューションに似ていますが、wiki ページで説明されている 3 つのソリューションがあります。

これがアービトレーター ソリューションの外観です。操作元のすべてのオブジェクトが同じ型から継承されている場合、静的クラス変数を使用して、オブジェクトのクラスにアービトレータを実装できます。

import java.util.concurrent.locks.Lock;

public void init()
{
  Lock arbitrator = new Lock();
}

public void meth1()
{
  arbitrator.lock();
  synchronized (obj1) {
    synchronized (obj2) {
      arbitrator.unlock();
      // Do Stuff
    }
  }
}

public void meth2()
{
  arbitrator.lock();
  synchronized (obj2) {
    synchronized (obj1) {
      arbitrator.unlock();
      // Do Stuff
    }
  }
}

Chandy/Misra ソリューションには多くのメッセージ パッシングが必要なため、実装するつもりはありませんが、ウィキペディアにはかなり適切な説明があります。

于 2015-01-15T20:18:44.667 に答える