2011-11-02 13 views
0

私は2つのロックinventoryLockとcurrencyLockを持つオブジェクトUserを持っています。多くの場合、これらのロックは個別に使用されます。簡単に作成されたデッドロックを回避するにはどうすればよいですか?

synchronized (user.inventoryLock) { 

// swap items 
tmp = user.inventory[x]; 
user.inventory[x] = user.inventory[y]; 
user.inventory[y] = tmp; 

} 

又は

synchronized (user.currencyLock) { 

if (user.money < loss) throw new Exception(); 
user.money -= loss; 

} 

しかし、時にはコードの一部は、両方のロックを必要とする:

synchronized (user.currencyLock) { 
synchronized (user.inventoryLock) { 

    if (user.money < item.price) throw new Exception(); 
    user.money -= item.price; 
    user.inventory[empty] = item; 

} 
} 

はシンプルだが、ちょうどこの例よりも、両方のロックを使用してコードのより多くのビットがあり、以前の経験から、複数のコードに同じ共有ロックが必要な場合、デッドロックの危険性があることがわかっています。

これを避けるにはどうすればよいでしょうか?

2つのオブジェクトを原子的にロックするメカニズムがありますか?

+0

あなたのコードは、カプセル化の深刻な欠如を示しています。メソッドを実行することなく、ユーザーの状態に直接アクセスします。状態をクラスにカプセル化して同期を集中化し、必要な同期がすべて完了したことを確認する必要があります。 Userクラス自体にこのサービスを提供するのではなく、ユーザーのすべてのクライアントを適切に同期させる必要があります。 –

+0

@JBNizetこれは単なるコード例です。実際のコードには、とりわけ、ユーザークラスが実行できないデータベース呼び出しが含まれます。 –

答えて

0

この質問を投稿した直後に私は簡単な解決法を考え出しました。すべてのコードが同じ順序でロックを取得していることを確認してください。そうすれば、どちらか一方を保持するスレッドが2つ存在することはありません。

自然順序がない場合は、アルファベット順で十分であり、覚えやすくなります。

3

常にあなたはいつもあなたがinventoryLockをロックする前currencyLockをロックし、決してcurrencyLockをロックしようとしていることを確認できた場合、デッドロックの要件の一つは、例えば、円形の待機パターン

で、他の前に1錠をロックあなたはすでにinventoryLockを持っていればあなたはうまくいくでしょう

+0

これも私が思いついたものなので、私は助けることはできませんが、同意します:) –

+0

もう一方を前にロックする手助けはできません。 *同じ順序で常にロックを取得する必要があります。* – EJP

0

デッドロックに必要な条件のうちの1つがcircular waitではありません。

+0

投稿した例だけでなく、両方のロックを必要とするコードがあります。私はそれを明らかにするでしょう。 –

関連する問題