{"id":43743,"date":"2015-09-16T19:34:06","date_gmt":"2015-09-16T16:34:06","guid":{"rendered":"http:\/\/www.javacodegeeks.com\/?p=43743"},"modified":"2023-12-13T11:51:57","modified_gmt":"2023-12-13T09:51:57","slug":"forkjoin-framework","status":"publish","type":"post","link":"https:\/\/www.javacodegeeks.com\/2015\/09\/forkjoin-framework.html","title":{"rendered":"Fork\/Join Framework"},"content":{"rendered":"<p><em>This article is part of our Academy Course titled <a href=\"http:\/\/www.javacodegeeks.com\/2015\/09\/java-concurrency-essentials.html\">Java Concurrency Essentials<\/a>.<\/p>\n<p>In this course, you will dive into the magic of concurrency. You will be introduced to the fundamentals of concurrency and concurrent code and you will learn about concepts like atomicity, synchronization and thread safety. Check it out <a href=\"http:\/\/www.javacodegeeks.com\/2015\/09\/java-concurrency-essentials.html\">here<\/a>!<\/em><\/p>\n<div class=\"toc\">\n<h4>Table Of Contents<\/h4>\n<dl>\n<dt><a href=\"#intro\">1. Introduction<\/a><\/dt>\n<dt><a href=\"#fork_join\">2. Fork\/Join<\/a><\/dt>\n<dd>\n<dl>\n<dt><a href=\"#recursive_task\">2.1. RecursiveTask<\/a><\/dt>\n<dt><a href=\"#recursive_action\">2.2. RecursiveAction<\/a><\/dt>\n<dt><a href=\"#comparison_executorservice\">2.3. ForkJoinPool and ExecutorService<\/a><\/dt>\n<\/dl>\n<\/dd>\n<\/dl>\n<\/div>\n<h2><a name=\"intro\"><\/a>1. Introduction<\/h2>\n<p>This article gives an introduction into the Fork\/Join Framework that is part of the JDK since version 1.7. It describes the basic features of the frameworks and provides some examples in order to provide some practical experience.<\/p>\n<h2><a name=\"fork_join\"><\/a>2. Fork\/Join<\/h2>\n<p>The base class of the Fork\/Join Framework is <code>java.util.concurrent.ForkJoinPool<\/code>. This class implements the two interfaces <code>Executor<\/code> and <code>ExecutorService<\/code> and subclasses the <code>AbstractExecutorService<\/code>. Hence the <code>ForkJoinPool<\/code> is basically a thread pool that takes special kinds of tasks, namely the <code>ForkJoinTask<\/code>. This class implements the already known interface <code>Future<\/code> and therewith methods like <code>get()<\/code>, <code>cancel()<\/code> and <code>isDone()<\/code>. Beyond that this class also provides two methods that gave the whole framework its name: <code>fork()<\/code> and <code>join()<\/code>.<\/p>\n<p>While a call of <code>fork()<\/code> will start an asynchronous execution of the task, a call of <code>join()<\/code> will wait until the task has finished and retrieve its result. Hence we can split a given task into multiple smaller tasks, fork each task and finally wait for all tasks to finish. This makes the implementation of complex problems easier.<\/p>\n<p>In computer science this approach is also known as divide-and-conquer approach. Every time a problem is too complex to solve at once, it is divided into multiple smaller and easier to solve problems. This can be written in pseudo code like that:<\/p>\n<pre class=\"brush:java\">\nif(problem.getSize() &gt; THRESHOLD) {\n\tSmallerProblem smallerProblem1 = new SmallerProblem();\n\tsmallerProblem1.fork();\n\tSmallerProblem smallerProblem2 = new SmallerProblem();\n\tsmallerProblem2.fork();\n\treturn problem.solve(smallerProblem1.join(), smallerProblem2.join());\n} else {\n\treturn problem.solve();\n}\n<\/pre>\n<p>First we check if the current size of the problem is bigger than a given threshold. If this is the case, we divide the problem into smaller problems, <code>fork()<\/code> each new task and then wait for the results by calling <code>join()<\/code>. As <code>join()<\/code> returns the results for each subtask, we have to find the best solution of the smaller problems and return this as our best solution. These steps are repeated until the given threshold is too low and the problem so small that we can compute its solution directly without further division.<\/p>\n<h3><a name=\"recursive_task\"><\/a>2.1. RecursiveTask<\/h3>\n<p>To grasp this procedure a little bit better, we implement an algorithm that finds the smallest number within an array of integer values. This problem is not one you would solve in your day to day work using a <code>ForkJoinPool<\/code>, but the following implementation shows the basic principles very clearly. In the <code>main()<\/code> method we setup an integer array with random values and create a new <code>ForkJoinPool<\/code>.<\/p>\n<p>The first parameter passed to its constructor is an indicator for the level of desired parallelism. Here we query the <code>Runtime<\/code> for the number of available CPU cores. Then we call the <code>invoke()<\/code> method and pass an instance of <code>FindMin<\/code>. <code>FindMin<\/code> extends the class <code>RecursiveTask<\/code>, which itself is a subclass of the <code>ForkJoinTask<\/code> mentioned before. The class <code>ForkJoinTask<\/code> has actually two subclasses: one is designed for tasks that return a value (<code>RecursiveTask<\/code>) and one that is designed for tasks without return value (<code>RecursiveAction<\/code>). The superclass forces us to implement <code>compute()<\/code>. Here we take a look at the given slice of the integer array and decide whether the current problem is too big to be solved immediately or not.<\/p>\n<p>When finding the smallest number within an array, the smallest problem size to be solved directly is to compare two elements with each other and return the smallest value of these. If we have currently more than two elements, we divide the array into two parts and find again the smallest number within these two parts. This is done by creating two new instances of <code>FindMin<\/code>.<div style=\"display:inline-block; margin: 15px 0;\"> <div id=\"adngin-JavaCodeGeeks_incontent_video-0\" style=\"display:inline-block;\"><\/div> <\/div><\/p>\n<p>The constructor is fed with the array and the start and end index. Then we start the execution of these two task asynchronously by calling <code>fork()<\/code>. This call submits the two tasks in the queue of the thread pool. The thread pool implements a strategy called work-stealing, i.e. if all other threads have enough to do, the current threads steals its work from one of the other tasks. This makes sure that tasks get executed as fast as possible.<\/p>\n<pre class=\"brush:java\">\npublic class FindMin extends RecursiveTask&lt;Integer&gt; {\n\tprivate static final long serialVersionUID = 1L;\n\tprivate int[] numbers;\n\tprivate int startIndex;\n\tprivate int endIndex;\n\n\tpublic FindMin(int[] numbers, int startIndex, int endIndex) {\n\t\tthis.numbers = numbers;\n\t\tthis.startIndex = startIndex;\n\t\tthis.endIndex = endIndex;\n\t}\n\n\t@Override\n\tprotected Integer compute() {\n\t\tint sliceLength = (endIndex - startIndex) + 1;\n\t\tif (sliceLength &gt; 2) {\n\t\t\tFindMin lowerFindMin = new FindMin(numbers, startIndex, startIndex + (sliceLength \/ 2) - 1);\n\t\t\tlowerFindMin.fork();\n\t\t\tFindMin upperFindMin = new FindMin(numbers, startIndex + (sliceLength \/ 2), endIndex);\n\t\t\tupperFindMin.fork();\n\t\t\treturn Math.min(lowerFindMin.join(), upperFindMin.join());\n\t\t} else {\n\t\t\treturn Math.min(numbers[startIndex], numbers[endIndex]);\n\t\t}\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tint[] numbers = new int[100];\n\t\tRandom random = new Random(System.currentTimeMillis());\n\t\tfor (int i = 0; i &lt; numbers.length; i++) {\n\t\t\tnumbers[i] = random.nextInt(100);\n\t\t}\n\t\tForkJoinPool pool = new ForkJoinPool(Runtime.getRuntime().availableProcessors());\n\t\tInteger min = pool.invoke(new FindMin(numbers, 0, numbers.length - 1));\n\t\tSystem.out.println(min);\n\t}\n}\n<\/pre>\n<h3><a name=\"recursive_action\"><\/a>2.2. RecursiveAction<\/h3>\n<p>As mentioned above next to <code>RecursiveTask<\/code> we also have the class <code>RecursiveAction<\/code>. In contrast to <code>RecursiveTask<\/code> it does not have to return a value, hence it can be used for asynchronous computations that can be directly performed on a given data structure. Such an example is the computation of a grayscale image out of a colored image. All we have to do is to iterate over each pixel of the image and compute the grayscale value out of the RGB value using the following formula:<\/p>\n<pre class=\"brush:java\">gray = 0.2126 * red + 0.7152 * green + 0.0722 * blue<\/pre>\n<p>The floating point numbers represent how much the specific color contributes to our human perception of gray. As the highest value is used for green, we can conclude that a grayscale image is computed to nearly 3\/4 just of the green part. So the basic implementation would look like this, assuming that image is our object representing the actual pixel data and the methods <code>setRGB()<\/code> and <code>getRGB()<\/code> are used to retrieve the actual RGB value:<\/p>\n<pre class=\"brush:java\">\nfor (int row = 0; row &lt; height; row++) {\n\tfor (int column = 0; column &lt; bufferedImage.getWidth(); column++) {\n\t\tint grayscale = computeGrayscale(image.getRGB(column, row));\n\t\timage.setRGB(column, row, grayscale);\n\t}\n}\n<\/pre>\n<p>The above implementation works fine on a single CPU machine. But if we have more than one CPU available, we might want to distribute this work to the available cores. So instead of iterating in two nested for loops over all pixels, we can use a <code>ForkJoinPool<\/code> and submit a new task for each row (or column) of the image. Once one row has been converted to grayscale, the current thread can work on another row.<\/p>\n<p>This principle is implemented in the following example:<\/p>\n<pre class=\"brush:java\">\npublic class GrayscaleImageAction extends RecursiveAction {\n\tprivate static final long serialVersionUID = 1L;\n\tprivate int row;\n\tprivate BufferedImage bufferedImage;\n\n\tpublic GrayscaleImageAction(int row, BufferedImage bufferedImage) {\n\t\tthis.row = row;\n\t\tthis.bufferedImage = bufferedImage;\n\t}\n\n\t@Override\n\tprotected void compute() {\n\t\tfor (int column = 0; column &lt; bufferedImage.getWidth(); column++) {\n\t\t\tint rgb = bufferedImage.getRGB(column, row);\n\t\t\tint r = (rgb &gt;&gt; 16) &amp; 0xFF;\n\t\t\tint g = (rgb &gt;&gt; 8) &amp; 0xFF;\n\t\t\tint b = (rgb &amp; 0xFF);\n\t\t\tint gray = (int) (0.2126 * (float) r + 0.7152 * (float) g + 0.0722 * (float) b);\n\t\t\tgray = (gray &lt;&lt; 16) + (gray &lt;&lt; 8) + gray;\n\t\t\tbufferedImage.setRGB(column, row, gray);\n\t\t}\n\t}\n\n\tpublic static void main(String[] args) throws IOException {\n\t\tForkJoinPool pool = new ForkJoinPool(Runtime.getRuntime().availableProcessors());\n\t\tBufferedImage bufferedImage = ImageIO.read(new File(args[0]));\n\t\tfor (int row = 0; row &lt; bufferedImage.getHeight(); row++) {\n\t\t\tGrayscaleImageAction action = new GrayscaleImageAction(row, bufferedImage);\n\t\t\tpool.execute(action);\n\t\t}\n\t\tpool.shutdown();\n\t\tImageIO.write(bufferedImage, \"jpg\", new File(args[1]));\n\t}\n}\n<\/pre>\n<p>Within our main() method we read the image using Java&#8217;s <code>ImageIO<\/code> class. The returned instance of <code>BufferedImage<\/code> has all the methods we need. We can query the number of rows and columns and retrieve and set the RGB value for each pixel. So all we do is to iterate over all rows and submit a new <code>GrayscaleImageAction<\/code> to our <code>ForkJoinPool<\/code>. The latter has received a hint about the available processors as a parameter to his constructor.<\/p>\n<p>The <code>ForkJoinPool<\/code> now starts the tasks asynchronously by invoking their <code>compute()<\/code> method. In this method we iterate over each row and update the corresponding RGB values by its grayscale value. After having submitted all tasks to the pool we wait in the main thread for the shutdown of the whole pool and then write the updated <code>BufferedImage<\/code> back to disc by using the <code>ImageIO.write()<\/code> method.<\/p>\n<p>Astonishingly we need only a few lines of code more than we would have needed without using the available processors. This again shows how much work we can save by using the available resources of the <code>java.util.concurrent<\/code> package.<\/p>\n<p>The <code>ForkJoinPool<\/code> offers three different methods for submitting a task:<\/p>\n<ul>\n<li><code>execute(ForkJoinTask)<\/code>: This methods executes the given task asynchronously. It has no return value.<\/li>\n<li><code>invoke(ForkJoinTask)<\/code>: This methods awaits the tasks return value.<\/li>\n<li><code>submit(ForkJoinTask)<\/code>: This methods executes the given task asynchronously. It returns a reference to the task itself. Hence the task reference can be used to query the result (as it implements the interface <code>Future<\/code>).<\/li>\n<\/ul>\n<p>With this knowledge it is clear why we have submitted the <code>GrayscaleImageAction<\/code> above using the method execute(). If we would have used <code>invoke()<\/code> instead, the main thread would have waited for the task to finish and we would not have utilized the available level of parallelism.<\/p>\n<p>We find the same differences when we take a closer look at the ForkJoinTask-API:<\/p>\n<ul>\n<li><code>ForkJoinTask.fork()<\/code>: The <code>ForkJoinTask<\/code> is executed asynchronously. It has no return value.<\/li>\n<li><code>ForkJoinTask.invoke()<\/code>: Immediately executes the <code>ForkJoinTask<\/code> and returns the result after completion.<\/li>\n<\/ul>\n<p>[ulp id=&#8217;DdINgEqoOovgkhhk-3&#8242;]<br \/>\n&nbsp;<\/p>\n<h3><a name=\"comparison_executorservice\"><\/a>2.3. ForkJoinPool and ExecutorService<\/h3>\n<p>Now that we know the <code>ExecutorService<\/code> and the <code>ForkJoinPool<\/code>, you may ask yourself why we should use the <code>ForkJoinPool<\/code> and not the <code>ExecutorService<\/code>. The difference between both is not that big. Both have <code>execute()<\/code> and <code>submit()<\/code> methods and take either instances of some common interface like <code>Runnable<\/code>, <code>Callable<\/code>, <code>RecursiveAction<\/code> or <code>RecursiveTask<\/code>.<\/p>\n<p>To understand the difference a little bit better, let&#8217;s try to implement the <code>FindMin<\/code> class from above using an <code>ExecutorService<\/code>:<\/p>\n<pre class=\"brush:java\">\npublic class FindMinTask implements Callable&lt;Integer&gt; {\n\tprivate int[] numbers;\n\tprivate int startIndex;\n\tprivate int endIndex;\n\tprivate ExecutorService executorService;\n\n\tpublic FindMinTask(ExecutorService executorService, int[] numbers, int startIndex, int endIndex) {\n\t\tthis.executorService = executorService;\n\t\tthis.numbers = numbers;\n\t\tthis.startIndex = startIndex;\n\t\tthis.endIndex = endIndex;\n\t}\n\n\tpublic Integer call() throws Exception {\n\t\tint sliceLength = (endIndex - startIndex) + 1;\n\t\tif (sliceLength &gt; 2) {\n\t\t\tFindMinTask lowerFindMin = new FindMinTask(executorService, numbers, startIndex, startIndex + (sliceLength \/ 2) - 1);\n\t\t\tFuture&lt;Integer&gt; futureLowerFindMin = executorService.submit(lowerFindMin);\n\t\t\tFindMinTask upperFindMin = new FindMinTask(executorService, numbers, startIndex + (sliceLength \/ 2), endIndex);\n\t\t\tFuture&lt;Integer&gt; futureUpperFindMin = executorService.submit(upperFindMin);\n\t\t\treturn Math.min(futureLowerFindMin.get(), futureUpperFindMin.get());\n\t\t} else {\n\t\t\treturn Math.min(numbers[startIndex], numbers[endIndex]);\n\t\t}\n\t}\n\t\n\tpublic static void main(String[] args) throws InterruptedException, ExecutionException {\n\t\tint[] numbers = new int[100];\n\t\tRandom random = new Random(System.currentTimeMillis());\n\t\tfor (int i = 0; i &lt; numbers.length; i++) {\n\t\t\tnumbers[i] = random.nextInt(100);\n\t\t}\n\t\tExecutorService executorService = Executors.newFixedThreadPool(64);\n\t\tFuture&lt;Integer&gt; futureResult = executorService.submit(new FindMinTask(executorService, numbers, 0, numbers.length-1));\n\t\tSystem.out.println(futureResult.get());\n\t\texecutorService.shutdown();\n\t}\n}\n<\/pre>\n<p>The code looks very similar, expect the fact that we <code>submit()<\/code> our tasks to the <code>ExecutorService<\/code> and then use the returned instance of <code>Future<\/code> to <code>wait()<\/code> for the result. The main difference between both implementations can be found at the point where the thread pool is constructed. In the example above, we create a fixed thread pool with 64(!) threads. Why did I choose such a big number? The reason here is, that calling <code>get()<\/code> for each returned <code>Future<\/code> block the current thread until the result is available. If we would only provide as many threads to the pool as we have CPUs available, the program would run out of resources and hang indefinitely.<\/p>\n<p>The <code>ForkJoinPool<\/code> implements the already mentioned work-stealing strategy, i.e. every time a running thread has to wait for some result; the thread removes the current task from the work queue and executes some other task ready to run. This way the current thread is not blocked and can be used to execute other tasks. Once the result for the originally suspended task has been computed the task gets executed again and the join() method returns the result. This is an important difference to the normal <code>ExecutorService<\/code> where you would have to block the current thread while waiting for a result.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This article is part of our Academy Course titled Java Concurrency Essentials. In this course, you will dive into the magic of concurrency. You will be introduced to the fundamentals of concurrency and concurrent code and you will learn about concepts like atomicity, synchronization and thread safety. Check it out here! Table Of Contents 1. &hellip;<\/p>\n","protected":false},"author":506,"featured_media":148,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[88,147,121,380],"class_list":["post-43743","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-core-java","tag-concurrency","tag-forkjoin","tag-performance-and-scalability","tag-threads"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Fork\/Join Framework - Java Code Geeks<\/title>\n<meta name=\"description\" content=\"This article is part of our Academy Course titled Java Concurrency Essentials. In this course, you will dive into the magic of concurrency. You will be\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.javacodegeeks.com\/2015\/09\/forkjoin-framework.html\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Fork\/Join Framework - Java Code Geeks\" \/>\n<meta property=\"og:description\" content=\"This article is part of our Academy Course titled Java Concurrency Essentials. In this course, you will dive into the magic of concurrency. You will be\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.javacodegeeks.com\/2015\/09\/forkjoin-framework.html\" \/>\n<meta property=\"og:site_name\" content=\"Java Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/javacodegeeks\" \/>\n<meta property=\"article:published_time\" content=\"2015-09-16T16:34:06+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-12-13T09:51:57+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/java-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Martin Mois\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:site\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Martin Mois\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/09\\\/forkjoin-framework.html#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/09\\\/forkjoin-framework.html\"},\"author\":{\"name\":\"Martin Mois\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/52c1e27ea19337c20d53df5286590760\"},\"headline\":\"Fork\\\/Join Framework\",\"datePublished\":\"2015-09-16T16:34:06+00:00\",\"dateModified\":\"2023-12-13T09:51:57+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/09\\\/forkjoin-framework.html\"},\"wordCount\":1489,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/09\\\/forkjoin-framework.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/java-logo.jpg\",\"keywords\":[\"Concurrency\",\"Fork\\\/Join\",\"Performance and Scalability\",\"Threads\"],\"articleSection\":[\"Core Java\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/09\\\/forkjoin-framework.html#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/09\\\/forkjoin-framework.html\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/09\\\/forkjoin-framework.html\",\"name\":\"Fork\\\/Join Framework - Java Code Geeks\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/09\\\/forkjoin-framework.html#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/09\\\/forkjoin-framework.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/java-logo.jpg\",\"datePublished\":\"2015-09-16T16:34:06+00:00\",\"dateModified\":\"2023-12-13T09:51:57+00:00\",\"description\":\"This article is part of our Academy Course titled Java Concurrency Essentials. In this course, you will dive into the magic of concurrency. You will be\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/09\\\/forkjoin-framework.html#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/09\\\/forkjoin-framework.html\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/09\\\/forkjoin-framework.html#primaryimage\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/java-logo.jpg\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/java-logo.jpg\",\"width\":150,\"height\":150},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/09\\\/forkjoin-framework.html#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Core Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\\\/core-java\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"Fork\\\/Join Framework\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"name\":\"Java Code Geeks\",\"description\":\"Java Developers Resource Center\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"alternateName\":\"JCG\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.javacodegeeks.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/javacodegeeks\",\"https:\\\/\\\/x.com\\\/javacodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/52c1e27ea19337c20d53df5286590760\",\"name\":\"Martin Mois\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/051a80ba18f758940b686c6c4bb4b5f02d59abe8cc42a95b3545f7565c7a40a1?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/051a80ba18f758940b686c6c4bb4b5f02d59abe8cc42a95b3545f7565c7a40a1?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/051a80ba18f758940b686c6c4bb4b5f02d59abe8cc42a95b3545f7565c7a40a1?s=96&d=mm&r=g\",\"caption\":\"Martin Mois\"},\"description\":\"Martin is a Java EE enthusiast and works for an international operating company. He is interested in clean code and the software craftsmanship approach. He also strongly believes in automated testing and continuous integration.\",\"sameAs\":[\"http:\\\/\\\/martinsdeveloperworld.wordpress.com\\\/\"],\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/author\\\/martin-mois\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Fork\/Join Framework - Java Code Geeks","description":"This article is part of our Academy Course titled Java Concurrency Essentials. In this course, you will dive into the magic of concurrency. You will be","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.javacodegeeks.com\/2015\/09\/forkjoin-framework.html","og_locale":"en_US","og_type":"article","og_title":"Fork\/Join Framework - Java Code Geeks","og_description":"This article is part of our Academy Course titled Java Concurrency Essentials. In this course, you will dive into the magic of concurrency. You will be","og_url":"https:\/\/www.javacodegeeks.com\/2015\/09\/forkjoin-framework.html","og_site_name":"Java Code Geeks","article_publisher":"https:\/\/www.facebook.com\/javacodegeeks","article_published_time":"2015-09-16T16:34:06+00:00","article_modified_time":"2023-12-13T09:51:57+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/java-logo.jpg","type":"image\/jpeg"}],"author":"Martin Mois","twitter_card":"summary_large_image","twitter_creator":"@javacodegeeks","twitter_site":"@javacodegeeks","twitter_misc":{"Written by":"Martin Mois","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.javacodegeeks.com\/2015\/09\/forkjoin-framework.html#article","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/2015\/09\/forkjoin-framework.html"},"author":{"name":"Martin Mois","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/52c1e27ea19337c20d53df5286590760"},"headline":"Fork\/Join Framework","datePublished":"2015-09-16T16:34:06+00:00","dateModified":"2023-12-13T09:51:57+00:00","mainEntityOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2015\/09\/forkjoin-framework.html"},"wordCount":1489,"commentCount":0,"publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2015\/09\/forkjoin-framework.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/java-logo.jpg","keywords":["Concurrency","Fork\/Join","Performance and Scalability","Threads"],"articleSection":["Core Java"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.javacodegeeks.com\/2015\/09\/forkjoin-framework.html#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.javacodegeeks.com\/2015\/09\/forkjoin-framework.html","url":"https:\/\/www.javacodegeeks.com\/2015\/09\/forkjoin-framework.html","name":"Fork\/Join Framework - Java Code Geeks","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2015\/09\/forkjoin-framework.html#primaryimage"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2015\/09\/forkjoin-framework.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/java-logo.jpg","datePublished":"2015-09-16T16:34:06+00:00","dateModified":"2023-12-13T09:51:57+00:00","description":"This article is part of our Academy Course titled Java Concurrency Essentials. In this course, you will dive into the magic of concurrency. You will be","breadcrumb":{"@id":"https:\/\/www.javacodegeeks.com\/2015\/09\/forkjoin-framework.html#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.javacodegeeks.com\/2015\/09\/forkjoin-framework.html"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/2015\/09\/forkjoin-framework.html#primaryimage","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/java-logo.jpg","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/java-logo.jpg","width":150,"height":150},{"@type":"BreadcrumbList","@id":"https:\/\/www.javacodegeeks.com\/2015\/09\/forkjoin-framework.html#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.javacodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"Java","item":"https:\/\/www.javacodegeeks.com\/category\/java"},{"@type":"ListItem","position":3,"name":"Core Java","item":"https:\/\/www.javacodegeeks.com\/category\/java\/core-java"},{"@type":"ListItem","position":4,"name":"Fork\/Join Framework"}]},{"@type":"WebSite","@id":"https:\/\/www.javacodegeeks.com\/#website","url":"https:\/\/www.javacodegeeks.com\/","name":"Java Code Geeks","description":"Java Developers Resource Center","publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"alternateName":"JCG","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.javacodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.javacodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.javacodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/javacodegeeks","https:\/\/x.com\/javacodegeeks"]},{"@type":"Person","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/52c1e27ea19337c20d53df5286590760","name":"Martin Mois","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/051a80ba18f758940b686c6c4bb4b5f02d59abe8cc42a95b3545f7565c7a40a1?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/051a80ba18f758940b686c6c4bb4b5f02d59abe8cc42a95b3545f7565c7a40a1?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/051a80ba18f758940b686c6c4bb4b5f02d59abe8cc42a95b3545f7565c7a40a1?s=96&d=mm&r=g","caption":"Martin Mois"},"description":"Martin is a Java EE enthusiast and works for an international operating company. He is interested in clean code and the software craftsmanship approach. He also strongly believes in automated testing and continuous integration.","sameAs":["http:\/\/martinsdeveloperworld.wordpress.com\/"],"url":"https:\/\/www.javacodegeeks.com\/author\/martin-mois"}]}},"_links":{"self":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/43743","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/users\/506"}],"replies":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/comments?post=43743"}],"version-history":[{"count":0,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/43743\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media\/148"}],"wp:attachment":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media?parent=43743"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/categories?post=43743"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/tags?post=43743"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}