I am playing around with Java lacthes and wrote a piece of code to calculate some stuff in a parallel manner. The data, basically consists of a Map that each map has a list of numbers as value. My goal is to sum up all the values for all keys in this map. To start with, I thought it is a good idea to get the sum of all values for each key in a separate thread (each key has its own separate thread) and at the end I add up what is returned from each thread to get the total sum. I use a simple CounDownLatch in my code:
public static void main(String[] args) throws InterruptedException, ExecutionException
{
//final CountDownLatch startGate = new CountDownLatch(1);
final CountDownLatch endGate = new CountDownLatch(3);
Map> data = new HashMap>();
Set summedData = new HashSet();
// populate the map with data
populateMap(data);
//separate the data with keys
//send each list to a new thread to process
for (String key : data.keySet())
{
final List list = data.get(key);
System.out.println(list);
//create a FutureTask
FutureTask future = new FutureTask(new Callable()
{
@Override
public Integer call() throws Exception
{
int sum = new Mapx(list).getSum();
endGate.countDown();
return sum;
}
});
Thread t = new Thread(future);
t.start();
System.out.println(t.getState());
summedData.add(future.get());
}
//keep the main method on hold until all the thread do their job
endGate.await();
//send to reduce
int total = new Reduce(summedData).addAll();
System.out.println(total);
}
My expectation is that, if the calculation of summing up all the items in a list for a key takes long, the thread running for this key, runs in the background and another thread for the next key starts to calculate. In other words, the calculations be done on in parallel. However, i see that this is not the case, and threads are run in serial. Can someone help me how I can achieve my goal and make this piece of code parallel?
You call future.get()
from within the loop. This method will block until the result is calculated, and therefore the loop will not continue until the other thread is done calculating, resulting in the serialized behavior you get.
To get the behavior you desire, you should have a loop launching all futureTasks on threads, and then a loop getting the results from all the FutureTask
s using get()
.
You're also probably better off submitting a Callable to an ExecutorService (see Executors), and the ExecutorService
will make the Future
for you.
In fact launching calculations in parrallel and waiting for their results is what an ExectorService
's invokeAll()
method does for you.
The use of CountDownLatch
is superfluous, as the Future
objects already have the necessary synchronization behavior on board.