In this post, I will write a piece of code which will create a deadlock situation and then i will discuss that way to resolve this scenario.
In my previous post, i written about Auto reload of configuration when any change happen, i discussed about refreshing your application configuration using a thread. As configurations are shared resources and when accessing via Threads, there is always chance of writing incorrect code and caught in deadlock situation.
In java, a deadlock is a situation where minimum two threads are holding lock on some different resource, and both are waiting for other’s resource to complete its task. And, none is able to leave the lock on resource it is holding. (See image below)
In above case, Thread- has A but need B to complete processing and Similarly Thread-2 has resource B but need A first.
Let write above scenario in java code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
package
thread;
public
class
ResolveDeadLockTest {
public
static
void
main(String[] args) {
ResolveDeadLockTest test =
new
ResolveDeadLockTest();
final
A a = test.
new
A();
final
B b = test.
new
B();
// Thread-1
Runnable block1 =
new
Runnable() {
public
void
run() {
synchronized
(a) {
try
{
// Adding delay so that both threads can start trying to
// lock resources
Thread.sleep(
100
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
// Thread-1 have A but need B also
synchronized
(b) {
System.out.println(
"In block 1"
);
}
}
}
};
// Thread-2
Runnable block2 =
new
Runnable() {
public
void
run() {
synchronized
(b) {
// Thread-2 have B but need A also
synchronized
(a) {
System.out.println(
"In block 2"
);
}
}
}
};
new
Thread(block1).start();
new
Thread(block2).start();
}
// Resource A
private
class
A {
private
int
i =
10
;
public
int
getI() {
return
i;
}
public
void
setI(
int
i) {
this
.i = i;
}
}
// Resource B
private
class
B {
private
int
i =
20
;
public
int
getI() {
return
i;
}
public
void
setI(
int
i) {
this
.i = i;
}
}
}
|
Running above code will result in deadlock for very obvious reasons (explained above). Now we have to solve this issue.
I believe, solution to any problem lies in identifying the root of problem. In our case, it is the pattern of accessing A and B, is main issue. So, to solve it, we will simply re-order the statements where code is accessing shared resources.
After rewriting the code, it will look like this ::
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
// Thread-1
Runnable block1 =
new
Runnable() {
public
void
run() {
synchronized
(b) {
try
{
// Adding delay so that both threads can start trying to
// lock resources
Thread.sleep(
100
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
// Thread-1 have A but need B also
synchronized
(a) {
System.out.println(
"In block 1"
);
}
}
}
};
// Thread-2
Runnable block2 =
new
Runnable() {
public
void
run() {
synchronized
(b) {
// Thread-2 have B but need A also
synchronized
(a) {
System.out.println(
"In block 2"
);
}
}
}
};
|
Run again above class, and you will not see any deadlock kind of situation. I hope, it will help you in avoiding deadlocks, and if encountered, in resolving them.
Happy Learning !!