Javaのデッドロック解析
コンカレントプログラムを作成するとき、デッドロックの問題は直面し、注意し、解消しなければならない.
デッドロックとは
Wikiの解釈は、「プロセスデッドロックとは、コンピュータ技術の名詞である.オペレーティングシステムまたはソフトウェアが動作する状態である.マルチワークシステムでは、1つまたは複数のプロセスがシステムリソースを待機し、システムリソースが同時にこのプロセス本体または他のプロセスに占有されると、デッドロックが形成される」というものである.
例えば、スレッド1がリソースAをロックし、リソースBにアクセスしようとすると、スレッド2がリソースBをロックし、リソースAにアクセスしようとすると、スレッド1と2はいずれも相手が必要とするリソースをロックし、相手が持っているリソースが解放されるのを待ってから自分の持っているリソースを解放し続けることができ、デッドロックが発生し、両方のスレッドはリソースを待つためにブロックされ、このような相互待ちを解除する手段がなければ,理論的には両者とも永遠に待っていることが想像できる.
この現象は次のように説明できます.
Thread 1 locks A,waits for B
Thread 2 locks B,wats for A
次にjavaコードを示します.
TreeNodeインスタンスが2つある場合:child,parent.スレッド(1)がparentを呼び出すと.addChild(child)は、スレッド(2)がchildを呼び出す.setParent(parent).スレッド(1)ではparentオブジェクトをロックし,スレッド(2)はchildオブジェクトを同時にロックした.このとき、スレッド(1)はchildを要求しようとする、childオブジェクトのロックを取得しようとするが、このロックはスレッド(2)に保持されているため、スレッド(1)は待機をブロックせざるを得ず、スレッド(2)がparentに実行する.addChildOnly(this)の時、彼はparentの鍵を手に入れようとしたが、残念なことに、この鍵はparentに占拠され、彼も待機をブロックせざるを得なかった.こうしてカップが発生し,スレッド(1)とスレッド(2)がブロックされて待機する.
より複雑なデッドロック現象
Thead 1 locks A,waits for B,
Thead 2 locks B,waits for C,
Thead 3 locks C,waits for D,
Thead 4 locks D,waits for A
データベースのデッドロック
1つのトランザクションは1つのレコード(a)をロックして変更され、現在、レコード(b)を変更する必要があります.彼がレコード(b)のロックを要求すると、残念ながら、レコード(b)は別のトランザクションにロックされ、さらにたまたま、レコード(b)を持つロックを持つトランザクションはこの時点でレコード(a)のロックを要求し、デッドロックが再び発生します.次の現象を説明します.
Transaction 1 request 1,locks record 1 for update
Transaction 2 request 1,locks record 2 for update
Transaction 1 request 2,locks record 2 for update
Transaction 2 request 2,locks record 1 for update
デッドロックとは
Wikiの解釈は、「プロセスデッドロックとは、コンピュータ技術の名詞である.オペレーティングシステムまたはソフトウェアが動作する状態である.マルチワークシステムでは、1つまたは複数のプロセスがシステムリソースを待機し、システムリソースが同時にこのプロセス本体または他のプロセスに占有されると、デッドロックが形成される」というものである.
例えば、スレッド1がリソースAをロックし、リソースBにアクセスしようとすると、スレッド2がリソースBをロックし、リソースAにアクセスしようとすると、スレッド1と2はいずれも相手が必要とするリソースをロックし、相手が持っているリソースが解放されるのを待ってから自分の持っているリソースを解放し続けることができ、デッドロックが発生し、両方のスレッドはリソースを待つためにブロックされ、このような相互待ちを解除する手段がなければ,理論的には両者とも永遠に待っていることが想像できる.
この現象は次のように説明できます.
Thread 1 locks A,waits for B
Thread 2 locks B,wats for A
次にjavaコードを示します.
public class TreeNode {
TreeNode parent = null;
List children = new ArrayList();
public synchronized void addChild(TreeNode child) {
if (!this.children.contains(child)) {
this.children.add(child);
child.setParentOnly(this);
}
}
public synchronized void addChildOnly(TreeNode child) {
if (!this.children.contains(child)) {
this.children.add(child);
}
}
public synchronized void setParent(TreeNode parent) {
this.parent = parent;
parent.addChildOnly(this);
}
public synchronized void setParentOnly(TreeNode parent) {
this.parent = parent;
}
}
TreeNodeインスタンスが2つある場合:child,parent.スレッド(1)がparentを呼び出すと.addChild(child)は、スレッド(2)がchildを呼び出す.setParent(parent).スレッド(1)ではparentオブジェクトをロックし,スレッド(2)はchildオブジェクトを同時にロックした.このとき、スレッド(1)はchildを要求しようとする、childオブジェクトのロックを取得しようとするが、このロックはスレッド(2)に保持されているため、スレッド(1)は待機をブロックせざるを得ず、スレッド(2)がparentに実行する.addChildOnly(this)の時、彼はparentの鍵を手に入れようとしたが、残念なことに、この鍵はparentに占拠され、彼も待機をブロックせざるを得なかった.こうしてカップが発生し,スレッド(1)とスレッド(2)がブロックされて待機する.
より複雑なデッドロック現象
Thead 1 locks A,waits for B,
Thead 2 locks B,waits for C,
Thead 3 locks C,waits for D,
Thead 4 locks D,waits for A
データベースのデッドロック
1つのトランザクションは1つのレコード(a)をロックして変更され、現在、レコード(b)を変更する必要があります.彼がレコード(b)のロックを要求すると、残念ながら、レコード(b)は別のトランザクションにロックされ、さらにたまたま、レコード(b)を持つロックを持つトランザクションはこの時点でレコード(a)のロックを要求し、デッドロックが再び発生します.次の現象を説明します.
Transaction 1 request 1,locks record 1 for update
Transaction 2 request 1,locks record 2 for update
Transaction 1 request 2,locks record 2 for update
Transaction 2 request 2,locks record 1 for update