Jul 17, 2013

Easily parallelizing code with Executors

Many times I've had to make some code work in parallel and I ended up doing things manually... You know a thread and a class to handle them with some funky logic that I have to check 100 times to get it right... that is usually what we end up doing because is the way we know (because it's the first thing we learn when dealing with parallelism). 

A few weeks ago I had to do the same thing again but this time I decides to do some reading before getting hands with the knowledge I have (yes, I know there is a first time for everything!). I read the concurrency chapter of Effective Java 2nd Edition and I noticed something really interesting that was enabled on java 5 the Executors
This cute little class allows you to specify the amount of threads you want to use to run some tasks, plain and simple!. Then you only have to create the tasks and submit them to the Executor,  after that you can either iterate the results or just let them be and wait for the Executor to finish. Yes it sounds really simple but if you are the same as I am, this is just pure words with no meaning, show me some code!

Well here it is, how to create and execute tasks with Executors:

  1. First you create an Executor,
    ExecutorService executor = Executors.newFixedThreadPool(cores);
    there a different kinds for different purposes (choose carefully to your needs). If you want to schedule a task instead of using timers take a look at the Scheduled Thread Pool, if you don't need a pool check the Single Thread Scheduled Executor. There are different kind of executor services and you can pass many things to them so take a deep dive before picking the right one.
  2. Identify if you will need results back from the tasks if so create a class and implement Callable, otherwise implement Runnable, both of them work perfectly fine with the Executor. DO NOT, I repeat DO NOT implement thread, there are many thing improved along the way in Java so you don't have to do this any more.
    • If you just want your task processed and she will do what she needs and then die in peace, use the Runnable interface and just execute your task
      executor.execute(new RunnableTask());
    • If you need the results Callable is the way to go, when you execute this tasks you have to use
      executor.submit(new CallableTask());
      this will give back a Future object that will contain the result for your task so don't lose it!
      One interesting fact is that to get the result from the Future object you have to call the get method on it, what is interesting is that if your task has not been processed yet the code will wait for it to execute! And you don't have to code those nasty synchronized methods and joining threads to get this, it's free so enjoy it!
  3. If you chose the Callable task you may want to iterate the results to process them, if not well basically you're done!
Note that the tasks will not be executed in order, if you want to do so, you can take a look at Google Guava that provides such capability. You can read more about it in here

And finally here is a small sample that you can download to check what happens.

1 comment:

  1. Nice overview :) concurrency can always be a pain.

    Another good resource for learning about concurrency in Java is Java Concurrency in Practice by Brian Goetz. Chapter 6 talks about Task Execution and the overall framework in detail. I highly recommend it.

    ReplyDelete