1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.lang3.concurrent.locks;
18
19 import static org.junit.jupiter.api.Assertions.assertEquals;
20 import static org.junit.jupiter.api.Assertions.assertNotNull;
21 import static org.junit.jupiter.api.Assertions.assertNotSame;
22 import static org.junit.jupiter.api.Assertions.assertTrue;
23
24 import java.time.Duration;
25 import java.util.concurrent.atomic.AtomicInteger;
26 import java.util.concurrent.locks.ReadWriteLock;
27 import java.util.concurrent.locks.ReentrantReadWriteLock;
28 import java.util.function.LongConsumer;
29
30 import org.apache.commons.lang3.AbstractLangTest;
31 import org.apache.commons.lang3.ArrayUtils;
32 import org.apache.commons.lang3.ThreadUtils;
33 import org.apache.commons.lang3.concurrent.locks.LockingVisitors.LockVisitor;
34 import org.apache.commons.lang3.concurrent.locks.LockingVisitors.StampedLockVisitor;
35 import org.apache.commons.lang3.function.FailableConsumer;
36 import org.junit.jupiter.api.Test;
37
38 public class LockingVisitorsTest extends AbstractLangTest {
39
40 private static final Duration SHORT_DELAY = Duration.ofMillis(100);
41 private static final Duration DELAY = Duration.ofMillis(1500);
42 private static final int NUMBER_OF_THREADS = 10;
43 private static final Duration TOTAL_DELAY = DELAY.multipliedBy(NUMBER_OF_THREADS);
44
45 protected boolean containsTrue(final boolean[] booleanArray) {
46 synchronized (booleanArray) {
47 return ArrayUtils.contains(booleanArray, true);
48 }
49 }
50
51 private void runTest(final Duration delay, final boolean exclusiveLock, final LongConsumer runTimeCheck,
52 final boolean[] booleanValues, final LockVisitor<boolean[], ?> visitor) throws InterruptedException {
53 final boolean[] runningValues = new boolean[10];
54
55 final long startTimeMillis = System.currentTimeMillis();
56 for (int i = 0; i < booleanValues.length; i++) {
57 final int index = i;
58 final FailableConsumer<boolean[], ?> consumer = b -> {
59 b[index] = false;
60 ThreadUtils.sleep(delay);
61 b[index] = true;
62 set(runningValues, index, false);
63 };
64 final Thread t = new Thread(() -> {
65 if (exclusiveLock) {
66 visitor.acceptWriteLocked(consumer);
67 } else {
68 visitor.acceptReadLocked(consumer);
69 }
70 });
71 set(runningValues, i, true);
72 t.start();
73 }
74 while (containsTrue(runningValues)) {
75 ThreadUtils.sleep(SHORT_DELAY);
76 }
77 final long endTimeMillis = System.currentTimeMillis();
78 for (final boolean booleanValue : booleanValues) {
79 assertTrue(booleanValue);
80 }
81
82
83 }
84
85 protected void set(final boolean[] booleanArray, final int offset, final boolean value) {
86 synchronized (booleanArray) {
87 booleanArray[offset] = value;
88 }
89 }
90
91 @Test
92 public void testCreate() {
93 final AtomicInteger res = new AtomicInteger();
94 final ReadWriteLock rwLock = new ReentrantReadWriteLock();
95 LockingVisitors.create(res, rwLock).acceptReadLocked(AtomicInteger::incrementAndGet);
96 assertEquals(1, res.get());
97 LockingVisitors.create(res, rwLock).acceptWriteLocked(AtomicInteger::incrementAndGet);
98 assertEquals(2, res.get());
99 }
100
101 @Test
102 public void testReentrantReadWriteLockExclusive() throws Exception {
103
104
105
106
107 final boolean[] booleanValues = new boolean[10];
108 runTest(DELAY, true, millis -> assertTrue(millis >= TOTAL_DELAY.toMillis()), booleanValues,
109 LockingVisitors.reentrantReadWriteLockVisitor(booleanValues));
110 }
111
112 @Test
113 public void testReentrantReadWriteLockNotExclusive() throws Exception {
114
115
116
117
118 final boolean[] booleanValues = new boolean[10];
119 runTest(DELAY, false, millis -> assertTrue(millis < TOTAL_DELAY.toMillis()), booleanValues,
120 LockingVisitors.reentrantReadWriteLockVisitor(booleanValues));
121 }
122
123 @Test
124 public void testResultValidation() {
125 final Object hidden = new Object();
126 final StampedLockVisitor<Object> lock = LockingVisitors.stampedLockVisitor(hidden);
127 final Object o1 = lock.applyReadLocked(h -> new Object());
128 assertNotNull(o1);
129 assertNotSame(hidden, o1);
130 final Object o2 = lock.applyWriteLocked(h -> new Object());
131 assertNotNull(o2);
132 assertNotSame(hidden, o2);
133 }
134
135 @Test
136 public void testStampedLockExclusive() throws Exception {
137
138
139
140
141 final boolean[] booleanValues = new boolean[10];
142 runTest(DELAY, true, millis -> assertTrue(millis >= TOTAL_DELAY.toMillis()), booleanValues,
143 LockingVisitors.stampedLockVisitor(booleanValues));
144 }
145
146 @Test
147 public void testStampedLockNotExclusive() throws Exception {
148
149
150
151
152 final boolean[] booleanValues = new boolean[10];
153 runTest(DELAY, false, millis -> assertTrue(millis < TOTAL_DELAY.toMillis()), booleanValues,
154 LockingVisitors.stampedLockVisitor(booleanValues));
155 }
156 }