Monday, August 2, 2010

Puzzle 64 - The Future is Secure

Java 1.5 adds a lot when it comes to threading. However thread programing is always a little tricky and Threading casually can lead to problems - With Great Power Come Great Responsibility. There is a Major bug (and a minor performance bug). Can you spot them both?

package com.test; import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; import java.util.concurrent.ScheduledThreadPoolExecutor; public class MyObject { public static Executor ex = new ScheduledThreadPoolExecutor(100); public static void main(String[] args) throws InterruptedException, ExecutionException { Tracker t = new Tracker(); Future<Tracker> f[] = new Future[1000]; for(int i=0;i<1000;i++){ /*The code in would be executed sometime in the future*/ f[i] = new FutureTask<Tracker>(new MyFutureTask(t)); ex.execute((Runnable) f[i]); } /*Wait for all the future task to complete!*/ for(int i=0;i<1000;i++){ f[i].get(); } /*Print out the number of future task that we have completed*/ System.out.println(t.getValue()); /*This prints the number of task executed - 1000*/ } } class MyFutureTask implements Callable<Tracker>{ Tracker myTracker; MyFutureTask(Tracker t) { myTracker = t; } @Override public synchronized Tracker call() throws Exception { /*Some complex business logic inserted at this point*/ int rand = new Random().nextInt(1000); Thread.sleep(rand); myTracker.increment(); return myTracker; } } class Tracker{ Integer value = 0; public void increment() { value++; } public int getValue(){ return value; } }


  1. At first glance looks like Callable isn't Runnable so it is invalid to do such cast; there is no point use object integer value inside tracker in case autoboxing always used to get value;

  2. major bug:
    class Tracker - not thread-safe, but we see modifications of Tracker instance from multiple threads.

    perf bug.

    unneeded cast to Runnable here:
    ex.execute((Runnable) f[i]);

  3. Tracker increment method should be synchronized. If it's not value will be modified by two threads at the same time and at the end it won't be 1000.

    Call shutdown on ScheduledThreadPoolExecutor. If you don't the threads will hang and the program won't stop.


Solution for this question?