0

I've read through the API documentation of the java.util.concurrent package, but have obviously misunderstood something. The overview says

A small toolkit of classes that support lock-free thread-safe programming on single variables.

However, a small test application shows that the AtomicInteger class does not provide thread-safety, at least when it is shared across threads (I accept that the getAndSet / increment methods themselves are at least atomic)

Test:

import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;

public class AtomicIntTest
{
    public static void main(String[] args) throws InterruptedException
    {
        AtomicInteger atomicInt = new AtomicInteger(0);
        WorkerThread w1 = new WorkerThread(atomicInt);
        WorkerThread w2 = new WorkerThread(atomicInt);
        w1.start();
        w2.start();
        w2.join(); // <-- As pointed out by StuartLC and BarrySW19, this should be w1.join(). This typo allows the program to produce variable results because it does not correctly wait for *both* threads to finish before outputting a result.
        w2.join();
        System.out.println("Final value: " + atomicInt.get());
    }

    public static class WorkerThread extends Thread
    {
        private AtomicInteger atomicInt = null;
        private Random random = new Random();

        public WorkerThread(AtomicInteger atomicInt)
        {
            this.atomicInt = atomicInt;
        }

        @Override
        public void run()
        {
            for (int i = 0; i < 500; i++)
            {
                this.atomicInt.incrementAndGet();
                try
                {
                    Thread.sleep(this.random.nextInt(50));
                }
                catch(InterruptedException e)
                {
                    e.printStackTrace();
                }
            }
        }
    }
}

When I run this class, I consistently get results ranging from around 950 to 1000, when I would expect to always see exactly 1000.

Can you explain why do I not get consistent results when two threads access this shared AtomicInteger variable? Have I misunderstood the thread-safety guarantee?

andrew-g-za
  • 967
  • 8
  • 13
  • 4
    You have `w2.join()` twice - one should be `w1.join()`, viz you aren't necessarily waiting for `w1` to complete before printing. – StuartLC Mar 20 '15 at 12:13
  • 1
    P.S.: "supports thread safe-programming" does not mean the same thing as "guarantees thread-safety." Even if every object in your program is "thread-safe" that will not make the program itself "thread-safe". You should work through the Oracle "concurrency" tutorial if you haven't already done: https://docs.oracle.com/javase/tutorial/essential/concurrency/index.html Pay special attention to the parts that talk about things that can go wrong and how to avoid them. – Solomon Slow Mar 20 '15 at 12:59
  • Hehehe, silly typo almost rocked my world view, thanks! – andrew-g-za Mar 20 '15 at 13:11

1 Answers1

1

Looks like a simple cut&paste error - you are joining to thread "w2" twice and never to "w1". At present, you would expect the thread "w1" to still be running half the time when you print the 'final' value.

BarrySW19
  • 3,759
  • 12
  • 26