Primive datatypes are not thread safe in java

We're going show you that the act of incrementing a variable isn't atomic in Java . For this purpose we've coded three classes:

Pizza:

package eu.albertomorales.OCAOCP.threads.example4;

public class Pizza {

public void increaseTemperature() {
    celsiusDegrees = celsiusDegrees + 1;
}

public int getTemperature() {
    return celsiusDegrees;
}

private int celsiusDegrees = 0;

}

Owen:

package eu.albertomorales.OCAOCP.threads.example4;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class Owen {

    private ExecutorService executor = Executors.newSingleThreadExecutor();

    public Future<Pizza> heat(Pizza pizza, int increment) {        
      return executor.submit(() -> {
          for (int n = 0; n < increment; n++) {
              Thread.sleep(10);
              pizza.increaseTemperature();
          }          
          return pizza;
      });
    }

    public void shutDown() {
        executor.shutdown();
    }
}

and IntegerSum (our entry point, class with main method)

package eu.albertomorales.OCAOCP.threads.example4;

import java.util.concurrent.Future;

public class IntegerSum {

  private void eat(Pizza pizza) {
    System.out.println(pizza.getTemperature());
  }

    private void doIt() throws InterruptedException {
      Owen owen = new Owen();
      Pizza pizza = new Pizza();
      Future<Pizza> future1 = owen.heat(pizza, 150);
      Future<Pizza> future2 = owen.heat(pizza, 150);
      while (!(future1.isDone() && future2.isDone())) {
        // System.out.print(".");
        System.out.println(
                  String.format(
                    "future1 is %s and future2 is %s", 
                    future1.isDone() ? "done" : "not done", 
                    future2.isDone() ? "done" : "not done"
                  )
                );
          Thread.yield();
        }
        owen.shutDown();
        eat(pizza);
    }

    public static void main(String[] args) throws InterruptedException {
        IntegerSum is2 = new IntegerSum();
        is2.doIt();
    }
}

The steps are:

  • Start (construct) the owen
  • Elaborate (construct) the pizza
  • Heat the pizza twice (150 temperature increments each cycle)
  • Turn off the owen
  • Eat the pizza.

In this last step we get the result, it should be 300 (150+150).

At first attemp, we get the right result. But a glimpse of the console output is enough to understand why:

future1 is not done and future2 is not done

future1 is not done and future2 is not done

...

future1 is done and future2 is not done

future1 is done and future2 is not done

...

(obvio) future1 is done and future2 is done

300

It is clear that the process is not parallel. Notice how the second warming cycle only starts once the first one is completed.

To make our program really multi-threaded we should use a different flavor of ExecutorService. Let’s see how the behavior of our example changes if we use a thread pool

executor = Executors.newCachedThreadPool()

instead of a single thread executor

executor = Executors.newSingleThreadExecutor()

This Executors.newCachedThreadPool factory method creates a kind of Thread Pool Executor that reuses previously used threads when they are available.

With a simple change in our Owen class now we have an executor which is able to use 2 simultaneous threads.

If we run the exact same code again, we’ll get the following output:

future1 is not done and future2 is not done

future1 is not done and future2 is not done

...

future1 is done and future2 is done

222

This is looking much better now. Notice how the 2 tasks start and finish running simultaneously.

But now the concurrency problem arises. 222 is not the expected result. That result demostrates that incrementing (temperature) variable is not thread safe.

There are several fixes. Obviously you can synchronize the increaseTemperature() method in the Pizza class. Or better, you can use AtomicInteger etc for thread-safe operations.

Alberto Morales Morales

Software craftsman. Passion for developing quality code that can be proud of. Happily married.

Madrid, Spain.