From f7341732fcea3791b12f717016486b66c66ad354 Mon Sep 17 00:00:00 2001 From: Mike Jensen Date: Fri, 3 Jan 2014 09:36:27 -0700 Subject: [PATCH] Added some tests which would fail with a simple volatile, but should work for the atomic implementations. --- test/AtomicIntegerConcurrentTest.java | 83 +++++++++++++++++++++++++ test/AtomicLongConcurrentTest.java | 83 +++++++++++++++++++++++++ test/AtomicReferenceConcurrentTest.java | 68 ++++++++++++++++++++ 3 files changed, 234 insertions(+) create mode 100644 test/AtomicIntegerConcurrentTest.java create mode 100644 test/AtomicLongConcurrentTest.java create mode 100644 test/AtomicReferenceConcurrentTest.java diff --git a/test/AtomicIntegerConcurrentTest.java b/test/AtomicIntegerConcurrentTest.java new file mode 100644 index 0000000000..664ba7edff --- /dev/null +++ b/test/AtomicIntegerConcurrentTest.java @@ -0,0 +1,83 @@ +import java.util.concurrent.atomic.AtomicInteger; + +public class AtomicIntegerConcurrentTest { + private static void runTest(final boolean increment, + final int threadCount, + final int iterationsPerThread) { + // we assume a 1ms delay per thread to try to get them all to start at the same time + final long startTime = System.currentTimeMillis() + threadCount; + final AtomicInteger result = new AtomicInteger(); + final AtomicInteger threadDoneCount = new AtomicInteger(); + + for (int i = 0; i < threadCount; i++) { + new Thread(new Runnable() { + @Override + public void run() { + try { + doOperation(); + } finally { + synchronized (threadDoneCount) { + threadDoneCount.incrementAndGet(); + + threadDoneCount.notifyAll(); + } + } + } + + private void doOperation() { + long sleepTime = System.currentTimeMillis() - startTime; + try { + Thread.sleep(sleepTime); + } catch (InterruptedException e) { + // let thread exit + return; + } + + boolean flip = true; + for (int i = 0; i < iterationsPerThread; i++) { + if (flip) { + if (increment) { + result.incrementAndGet(); + } else { + result.decrementAndGet(); + } + flip = false; + } else { + if (increment) { + result.getAndIncrement(); + } else { + result.getAndDecrement(); + } + flip = true; + } + } + } + }).start(); + } + + synchronized (threadDoneCount) { + while (threadDoneCount.get() < threadCount) { + try { + threadDoneCount.wait(); + } catch (InterruptedException e) { + // let thread exit + return; + } + } + } + + int expectedResult = threadCount * iterationsPerThread; + if (! increment) { + expectedResult *= -1; + } + int resultValue = result.get(); + if (resultValue != expectedResult) { + throw new IllegalStateException(resultValue + " != " + expectedResult); + } + } + + public static void main(String[] args) { + runTest(true, 10, 100); + runTest(false, 10, 100); + } +} diff --git a/test/AtomicLongConcurrentTest.java b/test/AtomicLongConcurrentTest.java new file mode 100644 index 0000000000..fd23b35c1f --- /dev/null +++ b/test/AtomicLongConcurrentTest.java @@ -0,0 +1,83 @@ +import java.util.concurrent.atomic.AtomicLong; + +public class AtomicLongConcurrentTest { + private static void runTest(final boolean increment, + final int threadCount, + final int iterationsPerThread) { + // we assume a 1ms delay per thread to try to get them all to start at the same time + final long startTime = System.currentTimeMillis() + threadCount; + final AtomicLong result = new AtomicLong(); + final AtomicLong threadDoneCount = new AtomicLong(); + + for (int i = 0; i < threadCount; i++) { + new Thread(new Runnable() { + @Override + public void run() { + try { + doOperation(); + } finally { + synchronized (threadDoneCount) { + threadDoneCount.incrementAndGet(); + + threadDoneCount.notifyAll(); + } + } + } + + private void doOperation() { + long sleepTime = System.currentTimeMillis() - startTime; + try { + Thread.sleep(sleepTime); + } catch (InterruptedException e) { + // let thread exit + return; + } + + boolean flip = true; + for (int i = 0; i < iterationsPerThread; i++) { + if (flip) { + if (increment) { + result.incrementAndGet(); + } else { + result.decrementAndGet(); + } + flip = false; + } else { + if (increment) { + result.getAndIncrement(); + } else { + result.getAndDecrement(); + } + flip = true; + } + } + } + }).start(); + } + + synchronized (threadDoneCount) { + while (threadDoneCount.get() < threadCount) { + try { + threadDoneCount.wait(); + } catch (InterruptedException e) { + // let thread exit + return; + } + } + } + + long expectedResult = threadCount * iterationsPerThread; + if (! increment) { + expectedResult *= -1; + } + long resultValue = result.get(); + if (resultValue != expectedResult) { + throw new IllegalStateException(resultValue + " != " + expectedResult); + } + } + + public static void main(String[] args) { + runTest(true, 10, 100); + runTest(false, 10, 100); + } +} diff --git a/test/AtomicReferenceConcurrentTest.java b/test/AtomicReferenceConcurrentTest.java new file mode 100644 index 0000000000..bd320cbdf3 --- /dev/null +++ b/test/AtomicReferenceConcurrentTest.java @@ -0,0 +1,68 @@ +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +public class AtomicReferenceConcurrentTest { + private static void runTest(final int threadCount, + final int iterationsPerThread) { + // we assume a 1ms delay per thread to try to get them all to start at the same time + final long startTime = System.currentTimeMillis() + threadCount; + final AtomicReference result = new AtomicReference(0); + final AtomicInteger threadDoneCount = new AtomicInteger(0); + + for (int i = 0; i < threadCount; i++) { + new Thread(new Runnable() { + @Override + public void run() { + try { + doOperation(); + } finally { + synchronized (threadDoneCount) { + threadDoneCount.incrementAndGet(); + + threadDoneCount.notifyAll(); + } + } + } + + private void doOperation() { + long sleepTime = System.currentTimeMillis() - startTime; + try { + Thread.sleep(sleepTime); + } catch (InterruptedException e) { + // let thread exit + return; + } + + for (int i = 0; i < iterationsPerThread; i++) { + Integer current = result.get(); + while (! result.compareAndSet(current, current + 1)) { + current = result.get(); + } + } + } + }).start(); + } + + synchronized (threadDoneCount) { + while (threadDoneCount.get() < threadCount) { + try { + threadDoneCount.wait(); + } catch (InterruptedException e) { + // let thread exit + return; + } + } + } + + long expectedResult = threadCount * iterationsPerThread; + Integer resultValue = result.get(); + if (resultValue != expectedResult) { + throw new IllegalStateException(resultValue + " != " + expectedResult); + } + } + + public static void main(String[] args) { + runTest(10, 100); + runTest(10, 100); + } +}