Fixing Checkstyle warnings.

Closes #532.
This commit is contained in:
Jochen Wiedmann 2020-05-31 22:18:02 +02:00
parent f544897e49
commit 3d4ed4a8ac
2 changed files with 113 additions and 90 deletions

View File

@ -25,11 +25,11 @@
/** Utility class for working with {@link java.util.concurrent.locks.Lock locked objects}. Locked objects are an
* alternative to synchronization.
*
*
* Locking is preferable, if there is a distinction between read access (multiple threads may have read
* access concurrently), and write access (only one thread may have write access at any given time.
* In comparison, synchronization doesn't support read access, because synchronized access is exclusive.
*
*
* Using this class is fairly straightforward:
* <ol>
* <li>While still in single thread mode, create an instance of {@link Locks.Lock} by calling
@ -54,7 +54,7 @@
* PrintStream ps = new Printstream(out);
* lock = Locks.lock(ps);
* }
*
*
* public void log(String message) {
* lock.runWriteLocked((ps) -&gt; ps.println(message));
* }
@ -62,55 +62,55 @@
* public void log(byte[] buffer) {
* lock.runWriteLocked((ps) -&gt; { ps.write(buffer); ps.println(); });
* }
* </pre>
* </pre>
*/
public class Locks {
public static class Lock<O extends Object> {
private final O lockedObject;
private final StampedLock lock = new StampedLock();
public static class Lock<O extends Object> {
private final O lockedObject;
private final StampedLock lock = new StampedLock();
public Lock(O lockedObject) {
this.lockedObject = Objects.requireNonNull(lockedObject, "Locked Object");
}
public Lock(O lockedObject) {
this.lockedObject = Objects.requireNonNull(lockedObject, "Locked Object");
}
public void runReadLocked(FailableConsumer<O,?> consumer) {
runLocked(lock.readLock(), consumer);
}
public void runReadLocked(FailableConsumer<O, ?> consumer) {
runLocked(lock.readLock(), consumer);
}
public void runWriteLocked(FailableConsumer<O,?> consumer) {
runLocked(lock.writeLock(), consumer);
}
public void runWriteLocked(FailableConsumer<O, ?> consumer) {
runLocked(lock.writeLock(), consumer);
}
public <T> T callReadLocked(FailableFunction<O,T,?> function) {
return callLocked(lock.readLock(), function);
}
public <T> T callReadLocked(FailableFunction<O, T, ?> function) {
return callLocked(lock.readLock(), function);
}
public <T> T callWriteLocked(FailableFunction<O,T,?> function) {
return callLocked(lock.writeLock(), function);
}
public <T> T callWriteLocked(FailableFunction<O, T, ?> function) {
return callLocked(lock.writeLock(), function);
}
protected void runLocked(long stamp, FailableConsumer<O,?> consumer) {
try {
consumer.accept(lockedObject);
} catch (Throwable t) {
throw Functions.rethrow(t);
} finally {
lock.unlock(stamp);
}
}
protected void runLocked(long stamp, FailableConsumer<O, ?> consumer) {
try {
consumer.accept(lockedObject);
} catch (Throwable t) {
throw Functions.rethrow(t);
} finally {
lock.unlock(stamp);
}
}
protected <T> T callLocked(long stamp, FailableFunction<O,T,?> function) {
try {
return function.apply(lockedObject);
} catch (Throwable t) {
throw Functions.rethrow(t);
} finally {
lock.unlock(stamp);
}
}
}
protected <T> T callLocked(long stamp, FailableFunction<O, T, ?> function) {
try {
return function.apply(lockedObject);
} catch (Throwable t) {
throw Functions.rethrow(t);
} finally {
lock.unlock(stamp);
}
}
}
public static <O extends Object> Locks.Lock<O> lock(O object) {
return new Locks.Lock<O>(object);
}
public static <O extends Object> Locks.Lock<O> lock(O object) {
return new Locks.Lock<O>(object);
}
}

View File

@ -16,58 +16,81 @@
*/
package org.apache.commons.lang3;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.function.LongConsumer;
import org.apache.commons.lang3.Functions.FailableConsumer;
import org.apache.commons.lang3.Locks.Lock;
import org.junit.jupiter.api.Test;
class LocksTest {
@Test
void testReadLock() throws Exception {
final long DELAY=3000;
final boolean[] booleanValues = new boolean[10];
final Lock<boolean[]> lock = Locks.lock(booleanValues);
final boolean[] runningValues = new boolean[10];
private static final int NUMBER_OF_THREADS = 10;
final long startTime = System.currentTimeMillis();
for (int i = 0; i < booleanValues.length; i++) {
final int index = i;
final FailableConsumer<boolean[],?> consumer = (b) -> {
b[index] = false;
Thread.sleep(DELAY);
b[index] = true;
modify(runningValues, index, false);
};
final Thread t = new Thread(() -> lock.runReadLocked(consumer));
modify(runningValues, i, true);
t.start();
}
while (someValueIsTrue(runningValues)) {
Thread.sleep(100);
}
final long endTime = System.currentTimeMillis();
for (int i = 0; i < booleanValues.length; i++) {
assertTrue(booleanValues[i]);
}
// If our threads would be running in exclusive mode, then we'd need
// at least DELAY milliseconds for each.
assertTrue((endTime-startTime) < booleanValues.length*DELAY);
}
@Test
void testReadLock() throws Exception {
final long DELAY=3000;
/** If our threads are running concurrently, then we expect to be faster
* than running one after the other.
*/
runTest(DELAY, false, (l) -> assertTrue(l < NUMBER_OF_THREADS*DELAY));
}
protected void modify(boolean[] booleanArray, int offset, boolean value) {
synchronized(booleanArray) {
booleanArray[offset] = value;
}
}
protected boolean someValueIsTrue(boolean[] booleanArray) {
synchronized(booleanArray) {
for (int i = 0; i < booleanArray.length; i++) {
if (booleanArray[i]) {
return true;
}
}
return false;
}
}
void testWriteLock() throws Exception {
final long DELAY = 100;
/** If our threads are running concurrently, then we expect to be no faster
* than running one after the other.
*/
runTest(DELAY, true, (l) -> assertTrue(l >= NUMBER_OF_THREADS*DELAY));
}
private void runTest(long delay, boolean exclusiveLock, LongConsumer runTimeCheck) throws InterruptedException {
final boolean[] booleanValues = new boolean[10];
final Lock<boolean[]> lock = Locks.lock(booleanValues);
final boolean[] runningValues = new boolean[10];
final long startTime = System.currentTimeMillis();
for (int i = 0; i < booleanValues.length; i++) {
final int index = i;
final FailableConsumer<boolean[], ?> consumer = (b) -> {
b[index] = false;
Thread.sleep(delay);
b[index] = true;
modify(runningValues, index, false);
};
final Thread t = new Thread(() -> {
if (exclusiveLock) {
lock.runWriteLocked(consumer);
} else {
lock.runReadLocked(consumer);
}
});
modify(runningValues, i, true);
t.start();
}
while (someValueIsTrue(runningValues)) {
Thread.sleep(100);
}
final long endTime = System.currentTimeMillis();
for (int i = 0; i < booleanValues.length; i++) {
assertTrue(booleanValues[i]);
}
runTimeCheck.accept(endTime-startTime);
}
protected void modify(boolean[] booleanArray, int offset, boolean value) {
synchronized(booleanArray) {
booleanArray[offset] = value;
}
}
protected boolean someValueIsTrue(boolean[] booleanArray) {
synchronized(booleanArray) {
for (int i = 0; i < booleanArray.length; i++) {
if (booleanArray[i]) {
return true;
}
}
return false;
}
}
}