cow: CopyOnWriteArrayList - deterministic iterator-snapshot and synchronizedList CME demos, JMH read/write throughput, and the addLast/removeFirst fix for a real concurrent-writer race
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
list before any iterator is taken = [Apple, Banana, Cherry]
|
||||
beforeWrite.next() = Apple
|
||||
[writer] added Date and Elderberry - list is now [Apple, Banana, Cherry, Date, Elderberry]
|
||||
|
||||
=== beforeWrite iterator was created BEFORE the write - draining the rest of it ===
|
||||
beforeWrite.next() = Banana
|
||||
beforeWrite.next() = Cherry
|
||||
beforeWrite never saw Date or Elderberry, and threw no exception.
|
||||
|
||||
=== afterWrite iterator is created AFTER the write - it sees the current array ===
|
||||
afterWrite.next() = Apple
|
||||
afterWrite.next() = Banana
|
||||
afterWrite.next() = Cherry
|
||||
afterWrite.next() = Date
|
||||
afterWrite.next() = Elderberry
|
||||
|
||||
Final list = [Apple, Banana, Cherry, Date, Elderberry]
|
||||
@@ -0,0 +1,11 @@
|
||||
[reader] it.next() = Apple
|
||||
[writer] syncList.add("Date") completed - list is now [Apple, Banana, Cherry, Date]
|
||||
[reader] it.next() threw ConcurrentModificationException, as expected
|
||||
|
||||
Exception actually thrown: java.util.ConcurrentModificationException
|
||||
|
||||
=== The fix: synchronize the WHOLE iteration yourself, as the Javadoc instructs ===
|
||||
holding the lock for the whole iteration - starting safeWriter now
|
||||
iterated 3 elements with no exception, because safeWriter
|
||||
cannot acquire the same monitor until this synchronized block exits
|
||||
after the block: syncList2 = [Apple, Banana, Cherry, Date]
|
||||
@@ -0,0 +1,4 @@
|
||||
-------------------------------------------------------------------------------
|
||||
Test set: com.ankurm.cow.CowClaimsTest
|
||||
-------------------------------------------------------------------------------
|
||||
Tests run: 7, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.088 s -- in com.ankurm.cow.CowClaimsTest
|
||||
@@ -0,0 +1,5 @@
|
||||
Benchmark (container) (writer) Mode Cnt Score Error Units
|
||||
ReadThroughputBenchmark.readSum COW NONE thrpt 3 1890.457 ± 486.709 ops/ms
|
||||
ReadThroughputBenchmark.readSum COW BACKGROUND thrpt 3 911.480 ± 70.801 ops/ms
|
||||
ReadThroughputBenchmark.readSum SYNC NONE thrpt 3 10.311 ± 23.312 ops/ms
|
||||
ReadThroughputBenchmark.readSum SYNC BACKGROUND thrpt 3 9.428 ± 12.790 ops/ms
|
||||
@@ -0,0 +1,9 @@
|
||||
Benchmark (container) (size) Mode Cnt Score Error Units
|
||||
WriteThroughputBenchmark.addRemove_fourConcurrentWriters COW 10 thrpt 3 2442.460 ± 10099.500 ops/ms
|
||||
WriteThroughputBenchmark.addRemove_fourConcurrentWriters COW 1000 thrpt 3 404.113 ± 92.677 ops/ms
|
||||
WriteThroughputBenchmark.addRemove_fourConcurrentWriters SYNC 10 thrpt 3 4256.370 ± 11472.184 ops/ms
|
||||
WriteThroughputBenchmark.addRemove_fourConcurrentWriters SYNC 1000 thrpt 3 2431.519 ± 10671.130 ops/ms
|
||||
WriteThroughputBenchmark.addRemove_oneWriter COW 10 thrpt 3 8590.710 ± 3673.510 ops/ms
|
||||
WriteThroughputBenchmark.addRemove_oneWriter COW 1000 thrpt 3 692.991 ± 1173.810 ops/ms
|
||||
WriteThroughputBenchmark.addRemove_oneWriter SYNC 10 thrpt 3 17149.052 ± 26734.246 ops/ms
|
||||
WriteThroughputBenchmark.addRemove_oneWriter SYNC 1000 thrpt 3 11819.476 ± 794.382 ops/ms
|
||||
@@ -0,0 +1,31 @@
|
||||
# Warmup Iteration 1: <failure>
|
||||
|
||||
java.lang.ArrayIndexOutOfBoundsException: Index 12 out of bounds for length 12
|
||||
at java.base/java.util.concurrent.CopyOnWriteArrayList.elementAt(CopyOnWriteArrayList.java:397)
|
||||
at java.base/java.util.concurrent.CopyOnWriteArrayList.remove(CopyOnWriteArrayList.java:538)
|
||||
at com.ankurm.cow.WriteThroughputBenchmark.addRemove_fourConcurrentWriters(WriteThroughputBenchmark.java:68)
|
||||
at com.ankurm.cow.jmh_generated.WriteThroughputBenchmark_addRemove_fourConcurrentWriters_jmhTest.addRemove_fourConcurrentWriters_thrpt_jmhStub(WriteThroughputBenchmark_addRemove_fourConcurrentWriters_jmhTest.java:147)
|
||||
at com.ankurm.cow.jmh_generated.WriteThroughputBenchmark_addRemove_fourConcurrentWriters_jmhTest.addRemove_fourConcurrentWriters_Throughput(WriteThroughputBenchmark_addRemove_fourConcurrentWriters_jmhTest.java:86)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.openjdk.jmh.runner.BenchmarkHandler$BenchmarkTask.call(BenchmarkHandler.java:527)
|
||||
at org.openjdk.jmh.runner.BenchmarkHandler$BenchmarkTask.call(BenchmarkHandler.java:504)
|
||||
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:328)
|
||||
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:545)
|
||||
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:328)
|
||||
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1090)
|
||||
java.lang.IndexOutOfBoundsException: Index 1002 out of bounds for length 1002
|
||||
at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:100)
|
||||
at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:106)
|
||||
at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:302)
|
||||
at java.base/java.util.Objects.checkIndex(Objects.java:365)
|
||||
at java.base/java.util.ArrayList.remove(ArrayList.java:552)
|
||||
at java.base/java.util.Collections$SynchronizedList.remove(Collections.java:2753)
|
||||
at com.ankurm.cow.WriteThroughputBenchmark.addRemove_fourConcurrentWriters(WriteThroughputBenchmark.java:68)
|
||||
at com.ankurm.cow.jmh_generated.WriteThroughputBenchmark_addRemove_fourConcurrentWriters_jmhTest.addRemove_fourConcurrentWriters_thrpt_jmhStub(WriteThroughputBenchmark_addRemove_fourConcurrentWriters_jmhTest.java:147)
|
||||
at com.ankurm.cow.jmh_generated.WriteThroughputBenchmark_addRemove_fourConcurrentWriters_jmhTest.addRemove_fourConcurrentWriters_Throughput(WriteThroughputBenchmark_addRemove_fourConcurrentWriters_jmhTest.java:86)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.openjdk.jmh.runner.BenchmarkHandler$BenchmarkTask.call(BenchmarkHandler.java:527)
|
||||
at org.openjdk.jmh.runner.BenchmarkHandler$BenchmarkTask.call(BenchmarkHandler.java:504)
|
||||
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:328)
|
||||
Reference in New Issue
Block a user