Problem
|
Zwei threads und zwei Resourcen,
|
|
jeder thread befindet sich in einem kritischen Abschnitt
einer Resource und möchte auf die jeweils andere Resource
zugreifen
|
Beispiel
|
class Deadlock {
Object lock1 = new SomeClass();
Object lock2 = new SomeClass();
public void foo() {
synchronized (lock1) {
synchronized (lock2) {
}
}
}
public void bar() {
synchronized (lock2) {
synchronized (lock1) {
}
}
}
}
|
| |
|
Die Erkennung von deadlocks ist nicht immmer so einfach!!!
|
2. Beispiel
|
Zyklische Struktur mit geschachtelten Monitoraufrufen
|
|
class X {
Y y1;
public
synchronized
void setY1(Y y) {
y1 = y;
}
public
synchronized
void foo() {
y1.bar();
}
public
synchronized
void bar() {
}
}
class Y {
X x1;
public
synchronized
void setX1(X x) {
x1 = x;
}
public
synchronized
void foo() {
x1.bar();
}
public
synchronized
void bar() {
}
}
public
class Deadlock2 {
X x;
Y y;
public Deadlock2() {
x = new X();
y = new Y();
x.setY1(y);
y.setX1(x);
t1 = new MyThread(x,y);
t2 = new MyThread(x,y);
t1.start();
t2.start();
}
}
|
|
Geschachtelte Monitor-Aufrufe für verschiedene Objekte bergen immer die Gefahr
von Verklemmungen.
|
|
Die Deadlock-Freiheit kann nicht durch Testen gezeigt
werden.
|
|
Die Deadlock-Freiheit kann nur durch systematische
Programm-Konstruktion erreicht werden.
|
|
nie synchronized-Methoden von anderen Objekten aus synchronized-Methoden
aufrufen.
Deadlocks erfordern immer mindestens zwei Threads. Der Grund hierfür
liegt darin, dass ein Thread, der in einen Monitor eingetreten ist,
wieder synchronized Blöcke dieses Monitors betreten darf
(Java Language Specification: Chapter 17
Threads and Locks: 17.5 Rules about Locks).
|
Beispiel |
Die beiden folgenden Programmfragmente erzeugen also, wie in einer früheren Version dieser Seite
fälschlicherweise dargestellt, keinen Deadlock,
da hier der gleicheThread mehrfach einen Monitor betritt. Dieses ist explizit erlaubt.
|
|
class X {
synchronized void f() {
f();
}
}
|
oder
|
|
class X {
void f() {
synchronized (this) {
synchronized (this) {
}
}
}
}
|