1

I'm fooling around with Java threads and I wrote this little program that creates several threads and runs them. In each thread a value is incremented multiple times. I used ThreadLocal class so that there's no contention for resources.

Source:

class MyValueHolder {

    public static ThreadLocal<Integer> value = new ThreadLocal<Integer>()
    {
        protected Integer initialValue() {
            return 0;
        }
    };

    public static void increment() {
        value.set(value.get() + 1);
    }

    public static Integer get() {
        return value.get();
    }
}

class MyTask implements Runnable {

    public static int counter;

    public MyTask() {
        counter++;
    }

    public void run() {

        for(int i = 0; i < 100; i++) {
            MyValueHolder.increment();
        }
        System.out.println("MyTask " + counter + ", Value " + MyValueHolder.get());
    }
}

public class Main {

    public static void main(String[] args) {

        ExecutorService es = Executors.newCachedThreadPool();

        for(int i = 0; i < 5; i++) {

            es.execute(new MyTask());
        }

        es.shutdownNow();
    }
}

After completion the output is most of the time this:

MyTask 5, Value 100
MyTask 5, Value 100
MyTask 5, Value 100
MyTask 5, Value 100
MyTask 5, Value 100

Which is what I'd expect to see.

However, sometimes I get something like this:

MyTask 2, Value 100
MyTask 4, Value 200
MyTask 5, Value 300
MyTask 5, Value 100
MyTask 5, Value 100

Now this is confusing. Why do the values differ even though each task does absolutely the same thing?

1
  • The order in which threads run is not guaranteed to be the order in which they were started. If your threads need to run in a particular order, use wait/notify, or a CountDownLatch. Commented Mar 20, 2016 at 20:29

3 Answers 3

5

The CachedThreadPoolExecutor reuses threads if a Runnable finishes before you have added all Runnables. If this happens the ThreadLocal of that thread will also be reused.

Sign up to request clarification or add additional context in comments.

Comments

1

Like stated above, ThreadLocal is being reused.

For counter, use AtomicInteger instead and set an initial value. counter++ is not an atomic operation, its two operations and is not thread safe.

2 Comments

The counter is currently not problematic, since it's value is incremented within the constructor - and the constructor is only called from the main method.
sorry, you are clearly right, the counter is printing incorrect numbers because the thread's run method is finished before all the constructors are called.
0

threads will keep running while you get an output you should wait for them to finish you can try isAlive(); with the threads

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.