fix issue #343 ReaderWriterLock unit tests fail on CI
This commit is contained in:
parent
150c4e0d5d
commit
e95cfe9292
@ -18,8 +18,7 @@ import java.util.stream.IntStream;
|
||||
* readers will be blocked until the writer is finished writing.
|
||||
*
|
||||
* <p>
|
||||
* This example use two mutex to demonstrate the concurrent access of multiple readers and
|
||||
* writers.
|
||||
* This example use two mutex to demonstrate the concurrent access of multiple readers and writers.
|
||||
*
|
||||
*
|
||||
* @author hongshuwei@gmail.com
|
||||
@ -33,15 +32,15 @@ public class App {
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
|
||||
ExecutorService executeService = Executors.newFixedThreadPool(1000);
|
||||
ExecutorService executeService = Executors.newFixedThreadPool(10);
|
||||
ReaderWriterLock lock = new ReaderWriterLock();
|
||||
|
||||
// Start 10 readers
|
||||
IntStream.range(0, 10)
|
||||
// Start 5 readers
|
||||
IntStream.range(0, 5)
|
||||
.forEach(i -> executeService.submit(new Reader("Reader " + i, lock.readLock())));
|
||||
|
||||
// Start 10 writers
|
||||
IntStream.range(0, 10)
|
||||
// Start 5 writers
|
||||
IntStream.range(0, 5)
|
||||
.forEach(i -> executeService.submit(new Writer("Writer " + i, lock.writeLock())));
|
||||
// In the system console, it can see that the read operations are executed concurrently while
|
||||
// write operations are exclusive.
|
||||
|
@ -34,7 +34,7 @@ public class Reader implements Runnable {
|
||||
*/
|
||||
public void read() throws InterruptedException {
|
||||
System.out.println(name + " begin");
|
||||
Thread.sleep(100);
|
||||
Thread.sleep(250);
|
||||
System.out.println(name + " finish");
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ public class Writer implements Runnable {
|
||||
*/
|
||||
public void write() throws InterruptedException {
|
||||
System.out.println(name + " begin");
|
||||
Thread.sleep(100);
|
||||
Thread.sleep(250);
|
||||
System.out.println(name + " finish");
|
||||
}
|
||||
}
|
||||
|
@ -1,87 +1,81 @@
|
||||
package com.iluwatar.reader.writer.lock;
|
||||
|
||||
import static org.mockito.Mockito.after;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.timeout;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.inOrder;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.mockito.InOrder;
|
||||
|
||||
/**
|
||||
* @author hongshuwei@gmail.com
|
||||
*/
|
||||
public class ReaderAndWriterTest {
|
||||
public class ReaderAndWriterTest extends StdOutTest {
|
||||
|
||||
ExecutorService executeService;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
executeService = Executors.newFixedThreadPool(2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify reader and writer can only get the lock to read and write orderly
|
||||
*/
|
||||
@Ignore // intermittent failures when executed on CI
|
||||
@Test
|
||||
public void testReadAndWrite() throws Exception {
|
||||
|
||||
ReaderWriterLock lock = new ReaderWriterLock();
|
||||
|
||||
Reader reader1 = spy(new Reader("Reader 1", lock.readLock()));
|
||||
Writer writer1 = spy(new Writer("Writer 1", lock.writeLock()));
|
||||
|
||||
executeService.submit(reader1);
|
||||
// Let reader1 execute first
|
||||
Thread.sleep(50);
|
||||
executeService.submit(writer1);
|
||||
|
||||
verify(reader1, timeout(99).atLeastOnce()).read();
|
||||
verify(writer1, after(10).never()).write();
|
||||
verify(writer1, timeout(100).atLeastOnce()).write();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify reader and writer can only get the lock to read and write orderly
|
||||
*/
|
||||
@Ignore // intermittent failures when executed on CI
|
||||
@Test
|
||||
public void testWriteAndRead() throws Exception {
|
||||
Reader reader1 = new Reader("Reader 1", lock.readLock());
|
||||
Writer writer1 = new Writer("Writer 1", lock.writeLock());
|
||||
|
||||
ExecutorService executeService = Executors.newFixedThreadPool(2);
|
||||
ReaderWriterLock lock = new ReaderWriterLock();
|
||||
|
||||
Reader reader1 = spy(new Reader("Reader 1", lock.readLock()));
|
||||
Writer writer1 = spy(new Writer("Writer 1", lock.writeLock()));
|
||||
|
||||
executeService.submit(writer1);
|
||||
// Let reader1 execute first
|
||||
Thread.sleep(50);
|
||||
executeService.submit(reader1);
|
||||
// Let reader1 execute first
|
||||
Thread.sleep(150);
|
||||
executeService.submit(writer1);
|
||||
|
||||
verify(writer1, timeout(99).atLeastOnce()).write();
|
||||
verify(reader1, after(10).never()).read();
|
||||
verify(reader1, timeout(100).atLeastOnce()).read();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
executeService.shutdown();
|
||||
try {
|
||||
executeService.awaitTermination(10, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
System.out.println("Error waiting for ExecutorService shutdown");
|
||||
}
|
||||
|
||||
final InOrder inOrder = inOrder(getStdOutMock());
|
||||
inOrder.verify(getStdOutMock()).println("Reader 1 begin");
|
||||
inOrder.verify(getStdOutMock()).println("Reader 1 finish");
|
||||
inOrder.verify(getStdOutMock()).println("Writer 1 begin");
|
||||
inOrder.verify(getStdOutMock()).println("Writer 1 finish");
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify reader and writer can only get the lock to read and write orderly
|
||||
*/
|
||||
@Test
|
||||
public void testWriteAndRead() throws Exception {
|
||||
|
||||
ExecutorService executeService = Executors.newFixedThreadPool(2);
|
||||
ReaderWriterLock lock = new ReaderWriterLock();
|
||||
|
||||
Reader reader1 = new Reader("Reader 1", lock.readLock());
|
||||
Writer writer1 = new Writer("Writer 1", lock.writeLock());
|
||||
|
||||
executeService.submit(writer1);
|
||||
// Let writer1 execute first
|
||||
Thread.sleep(150);
|
||||
executeService.submit(reader1);
|
||||
|
||||
executeService.shutdown();
|
||||
try {
|
||||
executeService.awaitTermination(10, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
System.out.println("Error waiting for ExecutorService shutdown");
|
||||
}
|
||||
|
||||
final InOrder inOrder = inOrder(getStdOutMock());
|
||||
inOrder.verify(getStdOutMock()).println("Writer 1 begin");
|
||||
inOrder.verify(getStdOutMock()).println("Writer 1 finish");
|
||||
inOrder.verify(getStdOutMock()).println("Reader 1 begin");
|
||||
inOrder.verify(getStdOutMock()).println("Reader 1 finish");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,25 +1,23 @@
|
||||
package com.iluwatar.reader.writer.lock;
|
||||
|
||||
import static org.mockito.Mockito.inOrder;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.timeout;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.mockito.InOrder;
|
||||
|
||||
/**
|
||||
* @author hongshuwei@gmail.com
|
||||
*/
|
||||
public class ReaderTest {
|
||||
public class ReaderTest extends StdOutTest {
|
||||
|
||||
/**
|
||||
* Verify that multiple readers can get the read lock concurrently
|
||||
*/
|
||||
@Ignore // intermittent failures when executed on CI
|
||||
@Test
|
||||
public void testRead() throws Exception {
|
||||
|
||||
@ -30,18 +28,23 @@ public class ReaderTest {
|
||||
Reader reader2 = spy(new Reader("Reader 2", lock.readLock()));
|
||||
|
||||
executeService.submit(reader1);
|
||||
Thread.sleep(150);
|
||||
executeService.submit(reader2);
|
||||
|
||||
// Read operation will hold the read lock 100 milliseconds, so here we guarantee that each
|
||||
// readers can read in 99 milliseconds to prove that multiple read can perform in the same time.
|
||||
verify(reader1, timeout(99).atLeastOnce()).read();
|
||||
verify(reader2, timeout(99).atLeastOnce()).read();
|
||||
|
||||
executeService.shutdown();
|
||||
try {
|
||||
executeService.awaitTermination(10, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
System.out.println("Error waiting for ExecutorService shutdown");
|
||||
}
|
||||
|
||||
// Read operation will hold the read lock 250 milliseconds, so here we prove that multiple reads
|
||||
// can be performed in the same time.
|
||||
final InOrder inOrder = inOrder(getStdOutMock());
|
||||
inOrder.verify(getStdOutMock()).println("Reader 1 begin");
|
||||
inOrder.verify(getStdOutMock()).println("Reader 2 begin");
|
||||
inOrder.verify(getStdOutMock()).println("Reader 1 finish");
|
||||
inOrder.verify(getStdOutMock()).println("Reader 2 finish");
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,53 @@
|
||||
package com.iluwatar.reader.writer.lock;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Date: 12/10/15 - 8:37 PM
|
||||
*
|
||||
* @author Jeroen Meulemeester
|
||||
*/
|
||||
public abstract class StdOutTest {
|
||||
|
||||
/**
|
||||
* The mocked standard out {@link PrintStream}, required since some actions don't have any
|
||||
* influence on accessible objects, except for writing to std-out using {@link System#out}
|
||||
*/
|
||||
private final PrintStream stdOutMock = mock(PrintStream.class);
|
||||
|
||||
/**
|
||||
* Keep the original std-out so it can be restored after the test
|
||||
*/
|
||||
private final PrintStream stdOutOrig = System.out;
|
||||
|
||||
/**
|
||||
* Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test
|
||||
*/
|
||||
@Before
|
||||
public void setUp() {
|
||||
System.setOut(this.stdOutMock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removed the mocked std-out {@link PrintStream} again from the {@link System} class
|
||||
*/
|
||||
@After
|
||||
public void tearDown() {
|
||||
System.setOut(this.stdOutOrig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mocked stdOut {@link PrintStream}
|
||||
*
|
||||
* @return The stdOut print stream mock, renewed before each test
|
||||
*/
|
||||
final PrintStream getStdOutMock() {
|
||||
return this.stdOutMock;
|
||||
}
|
||||
|
||||
}
|
@ -1,26 +1,23 @@
|
||||
package com.iluwatar.reader.writer.lock;
|
||||
|
||||
import static org.mockito.Mockito.after;
|
||||
import static org.mockito.Mockito.inOrder;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.timeout;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.mockito.InOrder;
|
||||
|
||||
/**
|
||||
* @author hongshuwei@gmail.com
|
||||
*/
|
||||
public class WriterTest {
|
||||
public class WriterTest extends StdOutTest {
|
||||
|
||||
/**
|
||||
* Verify that multiple writers will get the lock in order.
|
||||
*/
|
||||
@Ignore // intermittent failures when executed on CI
|
||||
@Test
|
||||
public void testWrite() throws Exception {
|
||||
|
||||
@ -32,23 +29,22 @@ public class WriterTest {
|
||||
|
||||
executeService.submit(writer1);
|
||||
// Let write1 execute first
|
||||
Thread.sleep(50);
|
||||
Thread.sleep(150);
|
||||
executeService.submit(writer2);
|
||||
|
||||
// Write operation will hold the write lock 100 milliseconds, so here we verify that when two
|
||||
// write excute concurrently
|
||||
// 1. The first write will get the lock and and write in 60ms
|
||||
// 2. The second writer will cannot get the lock when first writer get the lock
|
||||
// 3. The second writer will get the lock as last
|
||||
verify(writer1, timeout(10).atLeastOnce()).write();
|
||||
verify(writer2, after(10).never()).write();
|
||||
verify(writer2, timeout(100).atLeastOnce()).write();
|
||||
|
||||
executeService.shutdown();
|
||||
try {
|
||||
executeService.awaitTermination(10, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
System.out.println("Error waiting for ExecutorService shutdown");
|
||||
}
|
||||
// Write operation will hold the write lock 250 milliseconds, so here we verify that when two
|
||||
// writer execute concurrently, the second writer can only writes only when the first one is
|
||||
// finished.
|
||||
final InOrder inOrder = inOrder(getStdOutMock());
|
||||
inOrder.verify(getStdOutMock()).println("Writer 1 begin");
|
||||
inOrder.verify(getStdOutMock()).println("Writer 1 finish");
|
||||
inOrder.verify(getStdOutMock()).println("Writer 2 begin");
|
||||
inOrder.verify(getStdOutMock()).println("Writer 2 finish");
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user