This is the nonfair scenario:
When a thread B asks to hold a lock, if the lock is already taken by another thread A. Then the thread B will be suspended. After thread A finished his job, it releases the lock, then thread B is resumed. However, B needs a period of time to be able to actually run it’s task from where it was suspended. And this period of time could be relatively long compared to another thread C who is asking for that exact same lock at the same time. If C could acquire the lock, does C’s job and release the lock before B even “wakes up” (the time between B’s resumed and B’s able to actually run), then it’s a win-win situation for B and C. Because C gets the lock and has it’s job done and releases the lock, while B’s “waking up” and B gets the lock no later than it otherwise would have.
In the fair scenario:
The C will be queued after B.
To set the fairness of a Lock, one can use the parametered constructor. I assume the non-fair lock is faster and I did the following test - 8 threads contenting the same lock and each thread increments the shared counter 100k times. Non-fair lock is 51 times faster than fair lock.
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
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ContentedResource {
private Lock lock;
private long counter = 0L;
public ContentedResource(boolean fair) {
lock = new ReentrantLock(fair);
}
public void increment() {
lock.lock();
try {
counter++;
} finally {
lock.unlock();
}
}
public long getCount() {
lock.lock();
try {
return counter;
} finally {
lock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
long durationFair = testDuration(true);
long durationNonFair = testDuration(false);
System.out.printf("Non-fair lock is [%d] times faster than fair lock.", (int)durationFair/durationNonFair);
}
private static long testDuration(boolean fair) throws InterruptedException {
ContentedResource contentedResource = new ContentedResource(fair);
ExecutorService threadPool = Executors.newFixedThreadPool(8);
long start = System.currentTimeMillis();
for (int i = 0; i < 8; i++) {
threadPool.execute(new Runnable() {
@Override
public void run() {
long i = 100_000;
while (i-- > 0) {
contentedResource.increment();
}
}
});
}
threadPool.shutdown();
threadPool.awaitTermination(1, TimeUnit.MINUTES);
long duration_millisecond = System.currentTimeMillis() - start;
System.out.printf("Fairness [%5s], count [%d], duration is [%d]ms\n", fair, contentedResource.getCount(),
duration_millisecond);
return duration_millisecond;
}
}
Output:
Fairness [ true], count [800000], duration is [7977]ms
Fairness [false], count [800000], duration is [156]ms
Non-fair lock is [51] times faster than fair lock.