Skip to content

Commit 3398bad

Browse files
committed
Merge pull request iluwatar#344 from hoswey/master
fix issue iluwatar#343 ReaderWriterLock unit tests fail on CI
2 parents 150c4e0 + e95cfe9 commit 3398bad

File tree

7 files changed

+114
-69
lines changed

7 files changed

+114
-69
lines changed

reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/App.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@
1818
* readers will be blocked until the writer is finished writing.
1919
*
2020
* <p>
21-
* This example use two mutex to demonstrate the concurrent access of multiple readers and
22-
* writers.
21+
* This example use two mutex to demonstrate the concurrent access of multiple readers and writers.
2322
*
2423
*
2524
* @author hongshuwei@gmail.com
@@ -33,15 +32,15 @@ public class App {
3332
*/
3433
public static void main(String[] args) {
3534

36-
ExecutorService executeService = Executors.newFixedThreadPool(1000);
35+
ExecutorService executeService = Executors.newFixedThreadPool(10);
3736
ReaderWriterLock lock = new ReaderWriterLock();
3837

39-
// Start 10 readers
40-
IntStream.range(0, 10)
38+
// Start 5 readers
39+
IntStream.range(0, 5)
4140
.forEach(i -> executeService.submit(new Reader("Reader " + i, lock.readLock())));
4241

43-
// Start 10 writers
44-
IntStream.range(0, 10)
42+
// Start 5 writers
43+
IntStream.range(0, 5)
4544
.forEach(i -> executeService.submit(new Writer("Writer " + i, lock.writeLock())));
4645
// In the system console, it can see that the read operations are executed concurrently while
4746
// write operations are exclusive.

reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/Reader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public void run() {
3434
*/
3535
public void read() throws InterruptedException {
3636
System.out.println(name + " begin");
37-
Thread.sleep(100);
37+
Thread.sleep(250);
3838
System.out.println(name + " finish");
3939
}
4040
}

reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/Writer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public void run() {
3434
*/
3535
public void write() throws InterruptedException {
3636
System.out.println(name + " begin");
37-
Thread.sleep(100);
37+
Thread.sleep(250);
3838
System.out.println(name + " finish");
3939
}
4040
}
Lines changed: 28 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,81 @@
11
package com.iluwatar.reader.writer.lock;
22

3-
import static org.mockito.Mockito.after;
4-
import static org.mockito.Mockito.spy;
5-
import static org.mockito.Mockito.timeout;
6-
import static org.mockito.Mockito.verify;
3+
import static org.mockito.Mockito.inOrder;
74

85
import java.util.concurrent.ExecutorService;
96
import java.util.concurrent.Executors;
107
import java.util.concurrent.TimeUnit;
118

12-
import org.junit.After;
13-
import org.junit.Before;
14-
import org.junit.Ignore;
159
import org.junit.Test;
10+
import org.mockito.InOrder;
1611

1712
/**
1813
* @author hongshuwei@gmail.com
1914
*/
20-
public class ReaderAndWriterTest {
15+
public class ReaderAndWriterTest extends StdOutTest {
2116

22-
ExecutorService executeService;
2317

24-
@Before
25-
public void setup() {
26-
executeService = Executors.newFixedThreadPool(2);
27-
}
2818

2919
/**
3020
* Verify reader and writer can only get the lock to read and write orderly
3121
*/
32-
@Ignore // intermittent failures when executed on CI
3322
@Test
3423
public void testReadAndWrite() throws Exception {
3524

3625
ReaderWriterLock lock = new ReaderWriterLock();
3726

38-
Reader reader1 = spy(new Reader("Reader 1", lock.readLock()));
39-
Writer writer1 = spy(new Writer("Writer 1", lock.writeLock()));
27+
Reader reader1 = new Reader("Reader 1", lock.readLock());
28+
Writer writer1 = new Writer("Writer 1", lock.writeLock());
4029

30+
ExecutorService executeService = Executors.newFixedThreadPool(2);
4131
executeService.submit(reader1);
4232
// Let reader1 execute first
43-
Thread.sleep(50);
33+
Thread.sleep(150);
4434
executeService.submit(writer1);
4535

46-
verify(reader1, timeout(99).atLeastOnce()).read();
47-
verify(writer1, after(10).never()).write();
48-
verify(writer1, timeout(100).atLeastOnce()).write();
36+
executeService.shutdown();
37+
try {
38+
executeService.awaitTermination(10, TimeUnit.SECONDS);
39+
} catch (InterruptedException e) {
40+
System.out.println("Error waiting for ExecutorService shutdown");
41+
}
4942

43+
final InOrder inOrder = inOrder(getStdOutMock());
44+
inOrder.verify(getStdOutMock()).println("Reader 1 begin");
45+
inOrder.verify(getStdOutMock()).println("Reader 1 finish");
46+
inOrder.verify(getStdOutMock()).println("Writer 1 begin");
47+
inOrder.verify(getStdOutMock()).println("Writer 1 finish");
5048
}
5149

5250
/**
5351
* Verify reader and writer can only get the lock to read and write orderly
5452
*/
55-
@Ignore // intermittent failures when executed on CI
5653
@Test
5754
public void testWriteAndRead() throws Exception {
5855

5956
ExecutorService executeService = Executors.newFixedThreadPool(2);
6057
ReaderWriterLock lock = new ReaderWriterLock();
6158

62-
Reader reader1 = spy(new Reader("Reader 1", lock.readLock()));
63-
Writer writer1 = spy(new Writer("Writer 1", lock.writeLock()));
59+
Reader reader1 = new Reader("Reader 1", lock.readLock());
60+
Writer writer1 = new Writer("Writer 1", lock.writeLock());
6461

6562
executeService.submit(writer1);
66-
// Let reader1 execute first
67-
Thread.sleep(50);
63+
// Let writer1 execute first
64+
Thread.sleep(150);
6865
executeService.submit(reader1);
6966

70-
verify(writer1, timeout(99).atLeastOnce()).write();
71-
verify(reader1, after(10).never()).read();
72-
verify(reader1, timeout(100).atLeastOnce()).read();
73-
74-
75-
}
76-
77-
@After
78-
public void tearDown() {
7967
executeService.shutdown();
8068
try {
8169
executeService.awaitTermination(10, TimeUnit.SECONDS);
8270
} catch (InterruptedException e) {
8371
System.out.println("Error waiting for ExecutorService shutdown");
8472
}
73+
74+
final InOrder inOrder = inOrder(getStdOutMock());
75+
inOrder.verify(getStdOutMock()).println("Writer 1 begin");
76+
inOrder.verify(getStdOutMock()).println("Writer 1 finish");
77+
inOrder.verify(getStdOutMock()).println("Reader 1 begin");
78+
inOrder.verify(getStdOutMock()).println("Reader 1 finish");
8579
}
8680
}
8781

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,23 @@
11
package com.iluwatar.reader.writer.lock;
22

3+
import static org.mockito.Mockito.inOrder;
34
import static org.mockito.Mockito.spy;
4-
import static org.mockito.Mockito.timeout;
5-
import static org.mockito.Mockito.verify;
65

76
import java.util.concurrent.ExecutorService;
87
import java.util.concurrent.Executors;
98
import java.util.concurrent.TimeUnit;
109

11-
import org.junit.Ignore;
1210
import org.junit.Test;
11+
import org.mockito.InOrder;
1312

1413
/**
1514
* @author hongshuwei@gmail.com
1615
*/
17-
public class ReaderTest {
16+
public class ReaderTest extends StdOutTest {
1817

1918
/**
2019
* Verify that multiple readers can get the read lock concurrently
2120
*/
22-
@Ignore // intermittent failures when executed on CI
2321
@Test
2422
public void testRead() throws Exception {
2523

@@ -30,18 +28,23 @@ public void testRead() throws Exception {
3028
Reader reader2 = spy(new Reader("Reader 2", lock.readLock()));
3129

3230
executeService.submit(reader1);
31+
Thread.sleep(150);
3332
executeService.submit(reader2);
3433

35-
// Read operation will hold the read lock 100 milliseconds, so here we guarantee that each
36-
// readers can read in 99 milliseconds to prove that multiple read can perform in the same time.
37-
verify(reader1, timeout(99).atLeastOnce()).read();
38-
verify(reader2, timeout(99).atLeastOnce()).read();
39-
4034
executeService.shutdown();
4135
try {
4236
executeService.awaitTermination(10, TimeUnit.SECONDS);
4337
} catch (InterruptedException e) {
4438
System.out.println("Error waiting for ExecutorService shutdown");
4539
}
40+
41+
// Read operation will hold the read lock 250 milliseconds, so here we prove that multiple reads
42+
// can be performed in the same time.
43+
final InOrder inOrder = inOrder(getStdOutMock());
44+
inOrder.verify(getStdOutMock()).println("Reader 1 begin");
45+
inOrder.verify(getStdOutMock()).println("Reader 2 begin");
46+
inOrder.verify(getStdOutMock()).println("Reader 1 finish");
47+
inOrder.verify(getStdOutMock()).println("Reader 2 finish");
48+
4649
}
4750
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package com.iluwatar.reader.writer.lock;
2+
3+
import org.junit.After;
4+
import org.junit.Before;
5+
6+
import java.io.PrintStream;
7+
8+
import static org.mockito.Mockito.mock;
9+
10+
/**
11+
* Date: 12/10/15 - 8:37 PM
12+
*
13+
* @author Jeroen Meulemeester
14+
*/
15+
public abstract class StdOutTest {
16+
17+
/**
18+
* The mocked standard out {@link PrintStream}, required since some actions don't have any
19+
* influence on accessible objects, except for writing to std-out using {@link System#out}
20+
*/
21+
private final PrintStream stdOutMock = mock(PrintStream.class);
22+
23+
/**
24+
* Keep the original std-out so it can be restored after the test
25+
*/
26+
private final PrintStream stdOutOrig = System.out;
27+
28+
/**
29+
* Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test
30+
*/
31+
@Before
32+
public void setUp() {
33+
System.setOut(this.stdOutMock);
34+
}
35+
36+
/**
37+
* Removed the mocked std-out {@link PrintStream} again from the {@link System} class
38+
*/
39+
@After
40+
public void tearDown() {
41+
System.setOut(this.stdOutOrig);
42+
}
43+
44+
/**
45+
* Get the mocked stdOut {@link PrintStream}
46+
*
47+
* @return The stdOut print stream mock, renewed before each test
48+
*/
49+
final PrintStream getStdOutMock() {
50+
return this.stdOutMock;
51+
}
52+
53+
}
Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,23 @@
11
package com.iluwatar.reader.writer.lock;
22

3-
import static org.mockito.Mockito.after;
3+
import static org.mockito.Mockito.inOrder;
44
import static org.mockito.Mockito.spy;
5-
import static org.mockito.Mockito.timeout;
6-
import static org.mockito.Mockito.verify;
75

86
import java.util.concurrent.ExecutorService;
97
import java.util.concurrent.Executors;
108
import java.util.concurrent.TimeUnit;
119

12-
import org.junit.Ignore;
1310
import org.junit.Test;
11+
import org.mockito.InOrder;
1412

1513
/**
1614
* @author hongshuwei@gmail.com
1715
*/
18-
public class WriterTest {
16+
public class WriterTest extends StdOutTest {
1917

2018
/**
2119
* Verify that multiple writers will get the lock in order.
2220
*/
23-
@Ignore // intermittent failures when executed on CI
2421
@Test
2522
public void testWrite() throws Exception {
2623

@@ -32,23 +29,22 @@ public void testWrite() throws Exception {
3229

3330
executeService.submit(writer1);
3431
// Let write1 execute first
35-
Thread.sleep(50);
32+
Thread.sleep(150);
3633
executeService.submit(writer2);
3734

38-
// Write operation will hold the write lock 100 milliseconds, so here we verify that when two
39-
// write excute concurrently
40-
// 1. The first write will get the lock and and write in 60ms
41-
// 2. The second writer will cannot get the lock when first writer get the lock
42-
// 3. The second writer will get the lock as last
43-
verify(writer1, timeout(10).atLeastOnce()).write();
44-
verify(writer2, after(10).never()).write();
45-
verify(writer2, timeout(100).atLeastOnce()).write();
46-
4735
executeService.shutdown();
4836
try {
4937
executeService.awaitTermination(10, TimeUnit.SECONDS);
5038
} catch (InterruptedException e) {
5139
System.out.println("Error waiting for ExecutorService shutdown");
5240
}
41+
// Write operation will hold the write lock 250 milliseconds, so here we verify that when two
42+
// writer execute concurrently, the second writer can only writes only when the first one is
43+
// finished.
44+
final InOrder inOrder = inOrder(getStdOutMock());
45+
inOrder.verify(getStdOutMock()).println("Writer 1 begin");
46+
inOrder.verify(getStdOutMock()).println("Writer 1 finish");
47+
inOrder.verify(getStdOutMock()).println("Writer 2 begin");
48+
inOrder.verify(getStdOutMock()).println("Writer 2 finish");
5349
}
5450
}

0 commit comments

Comments
 (0)