Friday 30 January 2015

Java8 Multi-threading ForkJoinPool: Dealing with exceptions

One of the main motivations behind the introduction of Java8 lambdas was the ability to be able to use multicores as easily as possible (see Mastering Lambdas: Java Programming in a Multicore World).  By simply changing your code from collection.stream()... to collection.parallelStream()... you have instant multi-threading at your disposal which brings with it all the CPU power on your machine.  (Let's ignore contention at this point.)

If you print out the names of the threads used by parallelStream you will notice that they are the same threads used by the ForkJoin framework and look something like this:

[ForkJoinPool.commonPool-worker-1]
[ForkJoinPool.commonPool-worker-2]

See Benjamin Winterberg's blog for a nicely worked example of this.

Now in Java 8 you can use this commonPool directly with the new method on ForkJoinPool commonPool().  This returns an instance of ForkJoinPool (which is an ExecutorService) with the commonPool of threads - the same ones that are used in parallelStream. This means that any work you do directly with the commonPool will play very nicely with work done in parallelStream especially the thread scheduling and work stealing between threads.

Let's work through an example of how you use ForkJoin especially in dealing with the tricky subject of exceptions.

Firstly obtain an instance of the commonPool by calling ForkJoin.commonPool().  You can submit tasks to it using the submit() method. Because we are using Java8 we can pass in lambda expressions which is really neat.  As with all ExecutorService implementations you can pass either instances of Runnable or Callable into submit().  When you pass a lambda into the submit method it will automatically turn it into a Runnable or a Callable by inspecting the method signature.

This leads to an interesting problem which highlights how lambdas work.  Supposing that you have a method of return type void (like a Runnable) but throws a checked exception (like a Callable).  See the method throwException() in the code listing below for such an example.  If you write this code it won't compile.

Future task1 = commonPool.submit(() -> {
            throwException("task 1");
        });
The reason for this is that the compiler assumes, because of the void return type, that you are trying to create a Runnable.  Of course a Runnable can't throw an Exception.  To get around this problem you need to force the compiler to understand that you are creating a Callable which is allowed to throw an Exception using this code trick.

Future task1 = commonPool.submit(() -> {
            throwException("task 1");
            return null;
        });
This is a bit messy but does the job. Arguably, the compiler, could have worked this out itself.

Two more things to highlight in the full code listing below.  One, the fact that you can see how many threads are going to be available in the pool using commonPool.getParallelism(). This can be adjusted with the parameter '-Djava.util.concurrent.ForkJoinPool.common.parallelism'. Two, notice how you can unwrap the ExecutionException so that your code can just present an IOException to its callers rather a rather non-specific ExecutionException.  Also note that this code fails on the first exception.  If you want to collect all the exceptions you would have to structure the code appropriately, possibly returning a List of Exceptions.  Or maybe more neatly throwing a custom exception containing a list of underlying exceptions. 


public class ForkJoinTest {
    public void run() throws IOException{
        ForkJoinPool commonPool = ForkJoinPool.commonPool();

        Future task1 = commonPool.submit(() -> {
            throwException("task 1");
            return null;
        });
        Future task2 = commonPool.submit(() -> {
            throwException("task 2");
            return null;
        });

        System.out.println("Do something while tasks being " +
                "executed on " + commonPool.getParallelism()
                + " threads");

        try {
            //wait on the result from task2
            task2.get();
            //wait on the result from task1
            task1.get();
        } catch (InterruptedException e) {
            throw new AssertionError(e);
        } catch (ExecutionException e) {
            Throwable innerException = e.getCause();
            if (innerException instanceof RuntimeException) {
                innerException = innerException.getCause();
                if(innerException instanceof IOException){
                    throw (IOException) innerException;
                }
            }
            throw new AssertionError(e);
        }
    }

    public void throwException(String message) throws IOException,
            InterruptedException {
        Thread.sleep(100);
        System.out.println(Thread.currentThread() 
            + " throwing IOException");
        throw new IOException("Throw exception for " + message);
    }

    public static void main(String[] args) throws IOException{
        new ForkJoinTest().run();
    }
}

18 comments:

  1. Thanks, nice tips

    ReplyDelete
  2. Thanks, i tried it with my own exception (which extends WebApplicationException which extends RuntimeException).

    Though, I didn't needed two levels of "getCause". Once was enough, then like you, a downCast to my Exception and a throw.
    2 years later, it still works perfectly !

    ReplyDelete
  3. Thanks, i tried it with my own exception (which extends WebApplicationException which extends RuntimeException).

    Though, I didn't needed two levels of "getCause". Once was enough, then like you, a downCast to my Exception and a throw.
    2 years later, it still works perfectly !

    ReplyDelete
  4. I am so happy to found your blog post because it's really very informative. Please keep writing this kind of blogs and I regularly visit this blog.This blog is the general information for the feature. You got a good work for these blog.We have a developing our creative content of this mind.Thank you for this blog. This for very interesting and useful.Java training in Chennai

    Java Online training in Chennai

    Java Course in Chennai

    Best JAVA Training Institutes in Chennai

    Java training in Bangalore

    Java training in Hyderabad

    Java Training in Coimbatore

    Java Training

    Java Online Training

    ReplyDelete

  5. I recently came across your article and have been reading along. I want to express my admiration of your writing skill and ability to make readers read from the beginning to the end. I would like to read newer posts and to share my thoughts with you.Your post is just outstanding! thanks for such a post,its really going great and great work.You have provided great knowledge

    Azure Training in Chennai

    Azure Training in Bangalore

    Azure Training in Hyderabad

    Azure Training in Pune

    Azure Training | microsoft azure certification | Azure Online Training Course

    Azure Online Training

    ReplyDelete
  6. This is a brilliant article, Given such a great amount of data in it, These kind of articles keeps the clients enthusiasm for the site, and continue sharing more ... good karma.
    Data Science Training In Chennai

    Data Science Online Training In Chennai

    Data Science Training In Bangalore

    Data Science Training In Hyderabad

    Data Science Training In Coimbatore

    Data Science Training

    Data Science Online Training

    ReplyDelete
  7. I feel really happy to have seen your webpage.I am feeling grateful to read this.you gave a nice information for us.please updating more stuff content...keep up!!


    Android Training in Chennai

    Android Online Training in Chennai

    Android Training in Bangalore

    Android Training in Hyderabad

    Android Training in Coimbatore

    Android Training

    Android Online Training

    ReplyDelete
  8. Thanks for one marvelous posting! I enjoyed reading it; you are a great author. I will make sure to bookmark your blog and may come back someday. I want to encourage that you continue your great posts, have a nice weekend!
    IELTS Coaching in chennai

    German Classes in Chennai

    GRE Coaching Classes in Chennai

    TOEFL Coaching in Chennai

    spoken english classes in chennai | Communication training

    ReplyDelete
  9. Really awesome post, informative and knowledgeable content. Keep sharing more stuff with us. Thank you.
    Data Science Training in Hyderabad

    ReplyDelete
  10. เกมสล็อตออนไลน์ เล่นสล็อตได้ง่ายๆ สนุกเพลิดเพลินได้ไม่มีเบื่อ ambbets.com เราให้คุณเป็นสมาชิกค่ายเกมสล็อตชั่นนำได้ง่ายๆ !! สมัคร ambbet ขั้นต่ำเพียง 50 บาทเท่านั้น สมัครรับโบันสฟรี 100% เครดิตฟรีไม่มีกั๊ก เเจกไม่อั้น ฝากถอน ไม่มีขั้นต่ำ ถอนเงินได้ไม่อั้น รวดเร็วด้วยระบบ Auto ทุกธุรกรรมทำได้ด้วยตัวเอง ปลอดภัย 100%

    ReplyDelete
  11. AMAZING..!!! I REALLY LIKE THIS WEBSITE SO MUCH IT’S ABSOLUTELY EXCELLENT TO ME IN RECENT TIMES I AM SIMPLY WAITING FOR YOUR NEXT BLOG Shuntaro Chishiya White Hoodie

    ReplyDelete
  12. I Was Eagerly Looking For Content Like This, Right To The Point And Detailed As Well Accordingly Depending Upon The Matter/Topic. You Have Managed This Greatly For Sure. 49ers Gold Jacket

    ReplyDelete
  13. Not very numerous individuals would really, the way you simply did. I am truly inspired that there is such a great amount of data about this subject have been revealed and you've put worth a valiant effort with so much class. Bengals Starter jacket

    ReplyDelete