Skip to content

Commit ba7ca00

Browse files
beatrichartzoldratlee
authored andcommitted
Add reentrant lock livelock demo (#19)
1 parent ea226ff commit ba7ca00

File tree

2 files changed

+108
-0
lines changed

2 files changed

+108
-0
lines changed

README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ Examples of concurrency problems you encountered in development are welcome to p
6060
- [Demo description](#demo-description-6)
6161
- [Problem statement](#problem-statement-6)
6262
- [Quickly run](#quickly-run-6)
63+
- [🍺 Livelock caused by reentrant locks](#-livelock-caused-by-reentrant-locks)
64+
- [Demo description](#demo-description-7)
65+
- [Problem statement](#problem-statement-7)
66+
- [Quickly run](#quickly-run-7)
6367

6468
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
6569

@@ -206,3 +210,25 @@ Task thread deadlocked.
206210
```bash
207211
mvn compile exec:java -Dexec.mainClass=com.oldratlee.fucking.concurrency.SymmetricLockDeadlockDemo
208212
```
213+
214+
## 🍺 Livelock caused by reentrant locks
215+
216+
\# For a problem description, see the paragraph about livelocks [in this article](https://www.baeldung.com/cs/deadlock-livelock-starvation#livelock)
217+
218+
Demo class [`ReentrantLockLivelockDemo`](src/main/java/com/oldratlee/fucking/concurrency/ReentrantLockLivelockDemo.java).
219+
220+
### Demo description
221+
222+
Two task threads are trying to acquire a lock that the other thread holds while holding their own lock.
223+
224+
### Problem statement
225+
226+
While the threads are releasing their own lock constantly, they are also re-locking it immediately, denying the other thread
227+
a chance to acquire both locks. Since both threads are not blocked from executing but blocked from doing meaningful work,
228+
this is a livelock.
229+
230+
### Quickly run
231+
232+
```bash
233+
mvn compile exec:java -Dexec.mainClass=com.oldratlee.fucking.concurrency.ReentrantLockLivelockDemo
234+
```
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package com.oldratlee.fucking.concurrency;
2+
3+
import java.util.concurrent.TimeUnit;
4+
import java.util.concurrent.locks.Lock;
5+
import java.util.concurrent.locks.ReentrantLock;
6+
7+
/**
8+
* @author Beat Richartz
9+
*/
10+
public class ReentrantLockLivelockDemo {
11+
private static final Lock lock1 = new ReentrantLock();
12+
private static final Lock lock2 = new ReentrantLock();
13+
14+
public static void main(String[] args) throws Exception {
15+
Thread thread1 = new Thread(ReentrantLockLivelockDemo::concurrencyCheckTask1);
16+
thread1.start();
17+
Thread thread2 = new Thread(ReentrantLockLivelockDemo::concurrencyCheckTask2);
18+
thread2.start();
19+
}
20+
21+
@SuppressWarnings("InfiniteLoopStatement")
22+
private static void concurrencyCheckTask1() {
23+
System.out.println("Started concurrency check task 1");
24+
int counter = 0;
25+
26+
while (counter++ < 10_000) {
27+
try {
28+
if (lock1.tryLock(50, TimeUnit.MILLISECONDS)) {
29+
System.out.println("Task 1 acquired lock 1");
30+
Thread.sleep(50);
31+
if (lock2.tryLock()) {
32+
System.out.println("Task 1 acquired lock 2");
33+
} else {
34+
System.out.println("Task 1 failed to acquire lock 2, releasing lock 1");
35+
lock1.unlock();
36+
continue;
37+
}
38+
}
39+
} catch (InterruptedException e) {
40+
e.printStackTrace();
41+
break;
42+
}
43+
44+
break;
45+
}
46+
47+
System.err.printf("Fuck! No meaningful work done in %s iterations of task 1.\n", counter);
48+
lock2.unlock();
49+
lock1.unlock();
50+
}
51+
52+
@SuppressWarnings("InfiniteLoopStatement")
53+
private static void concurrencyCheckTask2() {
54+
System.out.println("Started concurrency check task 2");
55+
56+
int counter = 0;
57+
while (counter++ < 10_000) {
58+
try {
59+
if (lock2.tryLock(50, TimeUnit.MILLISECONDS)) {
60+
System.out.println("Task 2 acquired lock 2");
61+
Thread.sleep(50);
62+
if (lock1.tryLock()) {
63+
System.out.println("Task 2 acquired lock 1");
64+
} else {
65+
System.out.println("Task 2 failed to acquire lock 1, releasing lock 2");
66+
lock2.unlock();
67+
continue;
68+
}
69+
}
70+
} catch (InterruptedException e) {
71+
e.printStackTrace();
72+
break;
73+
}
74+
75+
break;
76+
}
77+
78+
System.err.printf("Fuck! No meaningful work done in %s iterations of task 2.\n", counter);
79+
lock2.unlock();
80+
lock1.unlock();
81+
}
82+
}

0 commit comments

Comments
 (0)