I encoded the next version of nextValue using compareAndSet , which is intended for use in an unsynchronized block. He passed your unit tests:
Oh, and I introduced new constants for MIN_VALUE and MAX_VALUE, but you can ignore them if you want.
static final int LOWEST_VALUE = Byte.MIN_VALUE; static final int HIGHEST_VALUE = Byte.MAX_VALUE; private AtomicInteger counter = new AtomicInteger(LOWEST_VALUE - 1); private AtomicInteger resetCounter = new AtomicInteger(0); public byte nextValue() { int oldValue; int newValue; do { oldValue = counter.get(); if (oldValue >= HIGHEST_VALUE) { newValue = LOWEST_VALUE; resetCounter.incrementAndGet(); if (isSlow) slowDownAndLog(10, "resetting"); } else { newValue = oldValue + 1; if (isSlow) slowDownAndLog(1, "missed"); } } while (!counter.compareAndSet(oldValue, newValue)); return (byte) newValue; }
compareAndSet() works in conjunction with get() to control concurrency.
At the beginning of your critical section, you execute get() to retrieve the old value. Then you can perform some function, depending only on the old value, to calculate the new value. Then you use compareAndSet() to set the new value. If AtomicInteger is no longer equal to the old value when compareAndSet() executed (due to concurrent activity), it fails, and you should start all over again.
If you have an extreme amount of concurrency and the calculation time is long, it is possible that compareAndSet() may not work many times before this happens, and it may be useful to collect statistics on this subject if you are worried.
I do not suggest that this is a better or worse approach than a simple synchronized block, as others have suggested, but I personally would probably use a synchronized block for simplicity.
EDIT : I will answer your real question: "Why is my work not working?"
Your code has:
int next = counter.incrementAndGet(); if (next > Byte.MAX_VALUE) {
Since these two lines are not protected by a synchronized block, several threads can execute them at the same time and everyone gets the values next > Byte.MAX_VALUE . Then they will all go into the synchronized block and return counter back to INITIAL_VALUE (one after the other when they are waiting for each other).
Over the years, a huge number of errors have been written related to an attempt to get a performance tuning without synchronizing when it does not seem necessary. For example, see Double Checked Locking