In den folgenden Abschnitten werden einige der häufigsten Deadlock-Szenarien beschrieben und Maßnahmen zu deren Vermeidung vorgeschlagen.
Daraufhin wird die folgende Ausnahme angezeigt:
com.ibm.websphere.objectgrid.plugins.LockDeadlockException: Nachricht
Diese Nachricht
stellt die Zeichenfolge dar, die als Parameter übergeben wird, wenn die Ausnahme erstellt und ausgelöst wird.Beschreibung: Wenn eine Transaktion oder ein Client eine Sperre für einen bestimmten Map-Eintrag anfordert, muss die Anforderung häufig warten, bis der aktuelle Client die Sperre freigibt, bevor die Anforderung übergeben wird. Wenn die Sperrenanforderung längere Zeit inaktiv bleibt und keine Sperre erteilt wird, wird eine Ausnahme des Typs "LockTimeoutException" erstellt, um ein Deadlock zu verhindern. Dies wird ausführlicher im folgenden Abschnitt beschrieben. Das Eintreten dieser Ausnahme ist bei der Verwendung einer pessimistischen Sperrstrategie wahrscheinlicher, weil die Sperre in diesem Fall erst beim Festschreiben der Transaktion freigegeben wird.
Weitere Details:
Die Ausnahme "LockTimeoutException" enthält die Methode getLockRequestQueueDetails, die eine Zeichenfolge zurückgibt. Sie können diese Methode verwenden, um eine detaillierte Beschreibung der Situation anzuzeigen, die die Ausnahme auslöst. Im Folgenden sehen Sie Beispielcode, der die Ausnahme abfängt und eine Fehlernachricht anzeigt:
try {
...
}
catch (LockTimeoutException lte) {
System.out.println(lte.getLockRequestQueueDetails());
}
lock request queue
−>[TX:163C269E−0105−4000−E0D7−5B3B090A571D, state =
Granted 5348 milli−seconds ago, mode = U]
−>[TX:163C2734−0105−4000−E024−5B3B090A571D, state =
Waiting for 5348 milli−seconds, mode = U]
−>[TX:163C328C−0105−4000−E114−5B3B090A571D, state =
Waiting for 1402 milli−seconds, mode = U]
try {
...
}
catch (ObjectGridException oe) {
Throwable Root = findRootCause( oe );
if (Root instanceof LockTimeoutException) {
LockTimeoutException lte = (LockTimeoutException)Root;
System.out.println(lte.getLockRequestQueueDetails());
}
}
Lösung: Eine Ausnahme des Typs "LockTimeoutException" verhindert potenzielle Deadlocks in Ihrer Anwendung. Eine Ausnahme dieses Typs wird generiert, wenn die Ausnahme eine definierte Wartezeit erreicht. Sie können die Wartezeit für die Ausnahme mit der Methode setLockTimeout(int) festlegen, die für die BackingMap verfügbar ist. Wenn in Ihrer Anwendung kein Deadlock vorhanden ist, passen Sie das Zeitlimit für die Sperre an, um die Ausnahme "LockTimeoutException" zu verhindern.
ObjectGrid objGrid = new ObjectGrid();
BackingMap bMap = objGrid.defineMap("MapName");
bMap.setLockTimeout(30);
Verwenden Sie das vorherige fest codierte Beispiel, um ObjectGrid- und Map-Eigenschaften zu definieren. Wenn Sie das ObjectGrid aus einer XML-Datei erstellen, setzen Sie das Attribut LockTimeout im Element "backingMap". Im Folgenden sehen Sie ein Beispiel für ein Element "backingMap", das den LockTimeout-Wert einer Map auf 30 Sekunden setzt.
<backingMap name="MapName" lockStrategy="PESSIMISTIC" lockTimeout="30">
Beschreibung: In den folgenden Szenarien wird beschrieben, wie Deadlocks auftreten können, wenn auf einen einzelnen Schlüssel mit einer S-Sperre zugegriffen wird, die später aktualisiert wird. Wenn dies zwei Transaktionen gleichzeitig tun, kann ein Deadlock auftreten.
Thread 1 | Thread 2 | ||
---|---|---|---|
1 | session.begin() | session.begin() | Jeder Thread erstellt eine unabhängige Transaktion. |
2 | map.get(key1) | map.get(key1) | Beiden Transaktionen wird eine S-Sperre für key1 erteilt. |
3 | map.update(Key1,v) | Keine U-Sperre. Die Aktualisierung wird im Transaktionscache durchgeführt. | |
4 | map.update(key1,v) | Keine U-Sperre. Die Aktualisierung wird im Transaktionscache durchgeführt. | |
5 | session.commit() | Blockiert: Die S-Sperre für key1 kann nicht in eine X-Sperre aktualisiert werden, weil Thread 2 eine S-Sperre hat. | |
6 | session.commit() | Deadlock: Die S-Sperre für key1 kann nicht in eine X-Sperre aktualisiert werden, weil T1 eine S-Sperre hat. |
Thread 1 | Thread 2 | ||
---|---|---|---|
1 | session.begin() | session.begin() | Jeder Thread erstellt eine unabhängige Transaktion. |
2 | map.get(key1) | Es wird eine S-Sperre für key1 erteilt. | |
3 | map.getForUpdate(key1,v) | Die S-Sperre wird in eine U-Sperre für key1 aktualisiert. | |
4 | map.get(key1) | Es wird eine S-Sperre für key1 erteilt. | |
5 | map.getForUpdate(key1,v) | Blockiert: T1 hat bereits eine U-Sperre. | |
6 | session.commit() | Deadlock: Die U-Sperre für key1 kann nicht aktualisiert werden. | |
7 | session.commit() | Deadlock: Die S-Sperre für key1 kann nicht aktualisiert werden. |
Thread 1 | Thread 2 | ||
---|---|---|---|
1 | session.begin() | session.begin() | Jeder Thread erstellt eine unabhängige Transaktion. |
2 | map.get(key1) | Es wird eine S-Sperre für key1 erteilt. | |
3 | map.getForUpdate(key1,v) | Die S-Sperre wird in eine U-Sperre für key1 aktualisiert. | |
4 | map.get(key1) | Es wird eine S-Sperre für key1 erteilt. | |
5 | map.getForUpdate(key1,v) | Blockiert: Thread 1 hat bereits eine U-Sperre. | |
6 | session.commit() | Deadlock: Die U-Sperre für key1 kann nicht in eine X-Sperre aktualisiert werden, weil Thread 2 eine S-Sperre hat. |
Thread 1 | Thread 2 | ||
---|---|---|---|
1 | session.begin() | session.begin() | Jeder Thread erstellt eine unabhängige Transaktion. |
2 | map.getForUpdate(key1) | Thread 1 wird eine U-Sperre für key1 erteilt. | |
3 | map.getForUpdate(key1) | Die Anforderung der U-Sperre wird blockiert. | |
4 | map.update(key1,v) | <blocked> | |
5 | session.commit() | <blocked> | Die U-Sperre für key1 kann erfolgreich in eine X-Sperre aktualisiert werden. |
6 | <released> | Die U-Sperre wird schließlich Thread 2 für key1 erteilt. | |
7 | map.update(key2,v) | Die U-Sperre wird Thread 2 für key2 erteilt. | |
8 | session.commit() | Die U-Sperre für key1 kann erfolgreich in eine X-Sperre aktualisiert werden. |
Beschreibung: In diesem Szenario wird beschrieben, was geschieht, wenn zwei Transaktionen versuchen, denselben Eintrag direkt zu aktualisieren und S-Sperren für andere Einträge halten.
Thread 1 | Thread 2 | ||
---|---|---|---|
1 | session.begin() | session.begin() | Jeder Thread erstellt eine unabhängige Transaktion. |
2 | map.get(key1) | map.get(key1) | Beiden Transaktionen wird eine S-Sperre für key1 erteilt. |
3 | map.get(key2) | map.get(key2) | Beiden Transaktionen wird eine S-Sperre für key2 erteilt. |
4 | map.update(key1,v) | Keine U-Sperre. Die Aktualisierung wird im Transaktionscache durchgeführt. | |
5 | map.update(key2,v) | Keine U-Sperre. Die Aktualisierung wird im Transaktionscache durchgeführt. | |
6. | session.commit() | Blockiert: Die S-Sperre für key1 kann nicht in eine X-Sperre aktualisiert werden, weil Thread 2 eine S-Sperre hat. | |
7 | session.commit() | Deadlock: Die S-Sperre für key2 kann nicht aktualisiert werden, weil Thread 1 eine S-Sperre hat. |
Thread 1 | Thread 2 | ||
---|---|---|---|
1 | session.begin() | session.begin() | Jeder Thread erstellt eine unabhängige Transaktion. |
2 | map.getForUpdate(key1) | Transaktion T1 wird eine U-Sperre für key1 erteilt. | |
3 | map.getForUpdate(key1) | Die Anforderung der U-Sperre wird blockiert. | |
4 | map.get(key2) | <blocked> | T1 wird eine S-Sperre für key2 erteilt. |
5 | map.update(key1,v) | <blocked> | |
6 | session.commit() | <blocked> | Die U-Sperre für key1 kann erfolgreich in eine X-Sperre aktualisiert werden. |
7 | <released> | Die U-Sperre wird schließlich T2 für key1 erteilt. | |
8 | map.get(key2) | T2 wird eine S-Sperre für key2 erteilt. | |
9 | map.update(key2,v) | T2 wird eine U-Sperre für key2 erteilt. | |
10 | session.commit() | Die U-Sperre für key1 kann erfolgreich in eine X-Sperre aktualisiert werden. |
Thread 1 | Thread 2 | ||
---|---|---|---|
1 | session.begin() | session.begin() | Jeder Thread erstellt eine unabhängige Transaktion. |
2 | map.getforUpdate(key1) | map.getForUpdate(key2) | Es werden erfolgreich U-Sperren für key1 und key2 erteilt. |
3 | map.get(key2) | map.get(key1) | Es wird eine S-Sperre für key1 und key2 erteilt. |
4 | map.update(key1,v) | map.update(key2,v) | |
5 | session.commit() | Die U-Sperre kann nicht in eine X-Sperre aktualisiert werden, weil T2 eine S-Sperre hat. | |
6 | session.commit() | Die U-Sperre kann nicht in eine X-Sperre aktualisiert werden, weil T1 eine S-Sperre hat. |