{"id":13398,"date":"2017-09-06T09:26:59","date_gmt":"2017-09-06T14:26:59","guid":{"rendered":"https:\/\/stackify.com\/?p=13398"},"modified":"2024-07-02T12:11:48","modified_gmt":"2024-07-02T12:11:48","slug":"java-thread-pools","status":"publish","type":"post","link":"https:\/\/stackify.com\/java-thread-pools\/","title":{"rendered":"Finally Getting the Most out of the Java Thread Pool"},"content":{"rendered":"<p><strong>Thread pool\u00a0is a core concept in multithreaded programming which, simply put, represents a collection of idle threads that can be used to execute tasks.<\/strong><\/p>\n<p>First, let&#8217;s outline a frame of reference for multithreading and why we may need to use a thread pool.<\/p>\n<p>A thread is an execution context that can run a set of instructions within a process &#8211; aka a running program. Multithreaded programming refers to using threads to execute multiple tasks concurrently. Of course, this paradigm is well supported on the JVM.<\/p>\n<p>Although this brings several advantages, primarily regarding the performance of a program, the multithreaded programming can also have disadvantages &#8211; such as increased complexity of the code, concurrency issues, unexpected results and adding the overhead of thread creation.<\/p>\n<p>In this article, we&#8217;re going to take a closer look at how the latter issue can be mitigated by using thread pools in Java.<\/p>\n<h2><strong>Why Use a Thread Pool?<\/strong><\/h2>\n<p>Creating and starting a thread can be an expensive process. By repeating this process every time we need to execute a task, we&#8217;re incurring a significant performance cost &#8211; which is exactly what we were attempting to improve by using threads.<\/p>\n<p>For a better understanding of the cost of creating and starting a thread, let&#8217;s see what the JVM actually does behind the scenes:<\/p>\n<ul>\n<li>it allocates memory for a thread stack that holds a frame for every thread method invocation<\/li>\n<li>each frame consists of a local variable array, return value, operand stack and constant pool<\/li>\n<li>some JVMs that support native methods also allocate a native stack<\/li>\n<li>each thread gets a program counter that tells it what the current instruction executed by the processor is<\/li>\n<li>the system creates a native thread corresponding to the Java thread<\/li>\n<li>descriptors relating to the thread are added to the JVM internal data structures<\/li>\n<li>the threads share the heap and method area<\/li>\n<\/ul>\n<p>Of course, the details of all this will depend on the JMV and the operating system.<\/p>\n<p>In addition, more threads mean more work for the system scheduler to decide which thread gets access to resources next.<\/p>\n<p><strong>A thread pool helps mitigate the issue of performance by reducing the number of threads needed and managing their lifecycle.<\/strong><\/p>\n<p>Essentially, threads are kept in the thread pool until they&#8217;re needed, after which they execute the task and return the pool to be reused later. This mechanism is especially helpful in systems that execute a large number of small tasks.<\/p>\n<h3><strong>Java Thread Pools<\/strong><\/h3>\n<p>Java provides its own implementations of the thread pool pattern, through objects called <strong>executors<\/strong>. These can be used through executor interfaces or directly through thread pool implementations &#8211; which does allow for finer-grained control.<\/p>\n<p>The <em>java.util.concurrent package<\/em> contains the following interfaces:<\/p>\n<ul>\n<li><em>Executor<\/em> &#8211; a simple interface for executing tasks<\/li>\n<li><em>ExecutorService<\/em> &#8211; a more complex interface which contains additional methods for managing the tasks and the executor itself<\/li>\n<li><em>ScheduledExecutorService<\/em> &#8211; extends <em>ExecutorService<\/em> with methods for scheduling the execution of a task<\/li>\n<\/ul>\n<p>Alongside these interfaces, the package also provides the <em>Executors<\/em> helper class for obtaining executor instances, as well as implementations for these interfaces.<\/p>\n<p>Generally, a Java thread pool is composed of:<\/p>\n<ul>\n<li>the pool of worker threads, responsible for managing the threads<\/li>\n<li>a thread factory that is responsible for creating new threads<\/li>\n<li>a queue of tasks waiting to be executed<\/li>\n<\/ul>\n<p>In the following sections, let&#8217;s see how the Java classes and interfaces that provide support for thread pools work in more detail.<\/p>\n<h4><strong>The <em>Executors<\/em> class and <em>Executor<\/em> interface<\/strong><\/h4>\n<p>The <em>Executors<\/em> class contains factory methods for creating different types of thread pools, while <em>Executor<\/em> is the simplest thread pool interface, with a single <em>execute()<\/em> method.<\/p>\n<p>Let&#8217;s use these two classes in conjunction with an example that creates a single-thread pool, then uses it to execute a simple statement:<\/p>\n<pre class=\"prettyprint\">Executor executor = Executors.newSingleThreadExecutor();\nexecutor.execute(() -&gt; System.out.println(\"Single thread pool test\"));<\/pre>\n<p><strong>Notice how the statement can be written as a lambda expression &#8211; which is inferred to be of <em>Runnable <\/em>type. <\/strong><\/p>\n<p>The <em>execute()<\/em> method runs the statement if a worker thread is available, or places the <em>Runnable<\/em> task in a queue to wait for a thread to become available.<\/p>\n<p><strong>Basically, the executor replaces the explicit creation and management of a thread.<\/strong><\/p>\n<p>The factory methods in the <em>Executors<\/em> class can create several types of thread pools:<\/p>\n<ul>\n<li><em>newSingleThreadExecutor()<\/em> &#8211; a thread pool with only one thread with an unbounded queue, which only executes one task at a time<\/li>\n<li><em>newFixedThreadPool()<\/em> &#8211; a thread pool with a fixed number of threads which share an unbounded queue; if all threads are active when a new task is submitted, they will wait in queue until a thread becomes available<\/li>\n<li><em>newCachedThreadPool()<\/em> &#8211; a thread pool that creates new threads as they are needed<\/li>\n<li><em>newWorkStealingThreadPool()<\/em> &#8211; a thread pool based on a &#8220;work-stealing&#8221; algorithm which will be detailed more in a later section<\/li>\n<\/ul>\n<p>Next, let&#8217;s take a look into what additional capabilities the <em>ExecutorService<\/em> interface.<\/p>\n<h4><em><strong>The ExecutorService<\/strong><\/em><\/h4>\n<p>One way to create an <em>ExecutorService<\/em> is to use the factory methods from the <em>Executors<\/em> class:<\/p>\n<pre class=\"prettyprint\">ExecutorService executor = Executors.newFixedThreadPool(10);<\/pre>\n<p><strong>Besides the<em> execute()<\/em> method, this interface also defines a similar <em>submit()<\/em> method that can return a <em>Future<\/em> object<\/strong>:<\/p>\n<pre class=\"prettyprint\">Callable&lt;Double&gt; callableTask = () -&gt; {\n    return employeeService.calculateBonus(employee);\n};\nFuture&lt;Double&gt; future = executor.submit(callableTask);\n\/\/ execute other operations\ntry {\n    if (future.isDone()) {\n        double result = future.get();\n    }\n} catch (InterruptedException | ExecutionException e) {\n    e.printStackTrace();\n}<\/pre>\n<p>As you can see in the example above, the <em>Future<\/em> interface can return the result of a task for <em>Callable<\/em> objects, and can also show the status of a task execution.<\/p>\n<p>The <em>ExecutorService<\/em> is not automatically destroyed when there are no tasks waiting to be executed, so <strong>to shut it down explicitly, you can use the <em>shutdown()<\/em> or <em>shutdownNow()<\/em> APIs<\/strong>:<\/p>\n<pre class=\"prettyprint\">executor.shutdown();<\/pre>\n<h4><em><strong>The ScheduledExecutorService<\/strong><\/em><\/h4>\n<p>This is a subinterface of <em>ExecutorService<\/em>\u00a0&#8211; which adds methods for scheduling tasks:<\/p>\n<pre class=\"prettyprint\">ScheduledExecutorService executor = Executors.newScheduledThreadPool(10);<\/pre>\n<p>The <em>schedule()<\/em> method specifies a task to be executed, a delay value and a <em>TimeUnit<\/em> for the value:<\/p>\n<pre class=\"prettyprint\">Future&lt;Double&gt; future = executor.schedule(callableTask, 2, TimeUnit.MILLISECONDS);<\/pre>\n<p>Furthermore, the interface defines two additional methods:<\/p>\n<pre class=\"prettyprint\">executor.scheduleAtFixedRate(\n  () -&gt; System.out.println(\"Fixed Rate Scheduled\"), 2, 2000, TimeUnit.MILLISECONDS);\n\nexecutor.scheduleWithFixedDelay(\n  () -&gt; System.out.println(\"Fixed Delay Scheduled\"), 2, 2000, TimeUnit.MILLISECONDS);<\/pre>\n<p>The <em>scheduleAtFixedRate()<\/em> method executes the task after 2 ms delay, then repeats it at every 2 seconds. Similarly, the <em>scheduleWithFixedDelay()<\/em> method starts the first execution after 2 ms, then repeats the task 2 seconds after the previous execution ends.<\/p>\n<p>In the following sections, let&#8217;s also go through two implementations of the <em>ExecutorService<\/em> interface: <em>ThreadPoolExecutor<\/em> and <em>ForkJoinPool<\/em>.<\/p>\n<h4><em><strong>The ThreadPoolExecutor<\/strong><\/em><\/h4>\n<p><strong>This thread pool implementation adds the ability to configure parameters<\/strong>, as well as extensibility hooks. The most convenient way to create a <em>ThreadPoolExecutor<\/em> object is by using the <em>Executors<\/em> factory methods:<\/p>\n<pre class=\"prettyprint\">ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);<\/pre>\n<p>In this manner, the thread pool is preconfigured for the most common cases. The number of threads can be controlled by setting the parameters:<\/p>\n<ul>\n<li><em>corePoolSize<\/em> and <em>maximumPoolSize<\/em>\u00a0&#8211; which represent the bounds of the number of threads<\/li>\n<li><em>keepAliveTime<\/em> &#8211; which determines the time to keep extra threads alive<\/li>\n<\/ul>\n<p>Digging a bit further, here&#8217;s how these parameters are used.<\/p>\n<p>If a task is submitted and fewer than <em>corePoolSize<\/em> threads are in execution, then a new thread is created. The same thing happens if there are more than <em>corePoolSize<\/em> but less than <em>maximumPoolSize<\/em> threads running, and the task queue is full. If there are more than <em>corePoolSize<\/em> threads which have been idle for longer than <em>keepAliveTime<\/em>, they will be terminated.<\/p>\n<p>In the example above, the<em> newFixedThreadPool()<\/em> method creates a thread pool with <em>corePoolSize<\/em>=<em>maximumPoolSize<\/em>=10, and a <em>keepAliveTime<\/em> of 0 seconds.<\/p>\n<p>If you use the<em> newCachedThreadPool()<\/em> method instead, this will create a thread pool with a maximumPoolSize of Integer.MAX_VALUE and a keepAliveTime of 60 seconds:<\/p>\n<pre class=\"prettyprint\">ThreadPoolExecutor cachedPoolExecutor \n  = (ThreadPoolExecutor) Executors.newCachedThreadPool();<\/pre>\n<p>The parameters can also be set through a constructor or through setter methods:<\/p>\n<pre class=\"prettyprint\">ThreadPoolExecutor executor = new ThreadPoolExecutor(\n  4, 6, 60, TimeUnit.SECONDS, new LinkedBlockingQueue&lt;Runnable&gt;()\n);\nexecutor.setMaximumPoolSize(8);<\/pre>\n<p><strong>A subclass of <em>ThreadPoolExecutor<\/em> is the <em>ScheduledThreadPoolExecutor<\/em> class<\/strong>, which implements the <em>ScheduledExecutorService<\/em> interface. You can create this type of thread pool by using the <em>newScheduledThreadPool()<\/em> factory method:<\/p>\n<pre class=\"prettyprint\">ScheduledThreadPoolExecutor executor \n  = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(5);<\/pre>\n<p>This creates a thread pool with a <em>corePoolSize<\/em> of 5, an unbounded <em>maximumPoolSize<\/em> and a <em>keepAliveTime<\/em> of 0 seconds.<\/p>\n<h4><strong>The <em>ForkJoinPool<\/em><\/strong><\/h4>\n<p>Another implementation of a thread pool is the <em>ForkJoinPool<\/em> class. This implements the <em>ExecutorService<\/em> interface and represents the central component of the fork\/join framework introduced in Java 7.<\/p>\n<p><strong>The fork\/join framework is based on a &#8220;work-stealing algorithm&#8221;<\/strong>. In simple terms, what this means is that threads that run out of tasks can &#8220;steal&#8221; work from other busy threads.<\/p>\n<p>A <em>ForkJoinPool<\/em> is well suited for cases when most tasks create other subtasks or when many small tasks are added to the pool from external clients.<\/p>\n<p>The workflow for using this thread pool typically looks something like this:<\/p>\n<ul>\n<li>create a <em>ForkJoinTask<\/em> subclass<\/li>\n<li>split the tasks into subtasks according to a condition<\/li>\n<li>invoke the tasks<\/li>\n<li>join the results of each task<\/li>\n<li>create an instance of the class and add it to the pool<\/li>\n<\/ul>\n<p><strong>To create a <em>ForkJoinTask<\/em>, you can choose one of its more commonly used subclasses, <em>RecursiveAction<\/em> or <em>RecursiveTask<\/em><\/strong> &#8211; if you need to return a result.<\/p>\n<p>Let&#8217;s implement an example of a class that extends <em>RecursiveTask<\/em> and calculates the factorial of a number by splitting it into subtasks depending on a THRESHOLD value:<\/p>\n<pre class=\"prettyprint\">public class FactorialTask extends RecursiveTask&lt;BigInteger&gt; {\n    private int start = 1;\n    private int n;\n    private static final int THRESHOLD = 20;\n\n    \/\/ standard constructors\n\n    @Override\n    protected BigInteger compute() {\n        if ((n - start) &gt;= THRESHOLD) {\n            return ForkJoinTask.invokeAll(createSubtasks())\n              .stream()\n              .map(ForkJoinTask::join)\n              .reduce(BigInteger.ONE, BigInteger::multiply);\n        } else {\n            return calculate(start, n);\n        }\n    }\n}<\/pre>\n<p>The main method that this class needs to implement is the overridden <em>compute()<\/em> method, which joins the result of each subtask.<\/p>\n<p>The actual splitting is done in the <em>createSubtasks()<\/em> method:<\/p>\n<pre class=\"prettyprint\">private Collection&lt;FactorialTask&gt; createSubtasks() {\n    List&lt;FactorialTask&gt; dividedTasks = new ArrayList&lt;&gt;();\n    int mid = (start + n) \/ 2;\n    dividedTasks.add(new FactorialTask(start, mid));\n    dividedTasks.add(new FactorialTask(mid + 1, n));\n    return dividedTasks;\n}<\/pre>\n<p>Finally, the <em>calculate()<\/em> method contains the multiplication of values in a range:<\/p>\n<pre class=\"prettyprint\">private BigInteger calculate(int start, int n) {\n    return IntStream.rangeClosed(start, n)\n      .mapToObj(BigInteger::valueOf)\n      .reduce(BigInteger.ONE, BigInteger::multiply);\n}<\/pre>\n<p>Next, tasks can be added to a thread pool:<\/p>\n<pre class=\"prettyprint\">ForkJoinPool pool = ForkJoinPool.commonPool();\nBigInteger result = pool.invoke(new FactorialTask(100));<\/pre>\n<h4><strong><em>ThreadPoolExecutor<\/em> vs.\u00a0<em>ForkJoinPool<\/em><\/strong><\/h4>\n<p>At first look, it seems that the fork\/join framework brings improved performance. However, this may not always be the case depending on the type of problem you need to solve.<\/p>\n<p>When choosing a thread pool, it&#8217;s important to also remember there is overhead caused by creating and managing threads and switching execution from one thread to another.<\/p>\n<p><strong>The <em>ThreadPoolExecutor<\/em> provides more control over the number of threads and the tasks that are executed by each thread.<\/strong> This makes it more suitable for cases when you have a smaller number of larger tasks that are executed on their own threads.<\/p>\n<p><strong>By comparison, the <em>ForkJoinPool<\/em> is based on threads &#8220;stealing&#8221; tasks from other threads.<\/strong> Because of this, it is best used to speed up work in cases when tasks can be broken up into smaller tasks.<\/p>\n<p>To implement the work-stealing algorithm, the fork\/join framework uses two types of queues:<\/p>\n<ul>\n<li>a central queue for all tasks<\/li>\n<li>a task queue for each thread<\/li>\n<\/ul>\n<p>When threads run out of tasks in their own queues, they attempt to take tasks from the other queues. To make the process more efficient, the thread queue uses a deque (double ended queue) data structure, with threads being added at one end and &#8220;stolen&#8221; from the other end.<\/p>\n<p>Here is a good visual representation of this process from <a href=\"http:\/\/www.h-online.com\/developer\/features\/The-fork-join-framework-in-Java-7-1762357.html\" rel=\"noopener\">The H Developer<\/a>:<\/p>\n<p>In contrast with this model, the <em>ThreadPoolExecutor<\/em> uses only one central queue.<\/p>\n<p>One last thing to remember is that the choosing a <em>ForkJoinPool<\/em> is only useful if the tasks create subtasks. Otherwise, it will function the same as a <em>ThreadPoolExecutor<\/em>, but with extra overhead.<\/p>\n<h3><strong>Tracing Thread Pool Execution<\/strong><\/h3>\n<p>Now that we have a good foundational understanding of the Java thread pool ecosystem let&#8217;s take a closer look at what happens during the execution of an application that uses a thread pool.<\/p>\n<p>By adding some logging statements in the constructor of <em>FactorialTask<\/em> and the <em>calculate()<\/em> method, you can follow the invocation sequence:<\/p>\n<pre class=\"prettyprint\">13:07:33.123 [main] INFO ROOT - New FactorialTask Created\n13:07:33.123 [main] INFO ROOT - New FactorialTask Created\n13:07:33.123 [main] INFO ROOT - New FactorialTask Created\n13:07:33.123 [main] INFO ROOT - New FactorialTask Created\n13:07:33.123 [ForkJoinPool.commonPool-worker-1] INFO ROOT - New FactorialTask Created\n13:07:33.123 [ForkJoinPool.commonPool-worker-1] INFO ROOT - New FactorialTask Created\n13:07:33.123 [main] INFO ROOT - New FactorialTask Created\n13:07:33.123 [main] INFO ROOT - New FactorialTask Created\n13:07:33.123 [main] INFO ROOT - Calculate factorial from 1 to 13\n13:07:33.123 [ForkJoinPool.commonPool-worker-1] INFO ROOT - New FactorialTask Created\n13:07:33.123 [ForkJoinPool.commonPool-worker-2] INFO ROOT - New FactorialTask Created\n13:07:33.123 [ForkJoinPool.commonPool-worker-1] INFO ROOT - New FactorialTask Created\n13:07:33.123 [ForkJoinPool.commonPool-worker-2] INFO ROOT - New FactorialTask Created\n13:07:33.123 [ForkJoinPool.commonPool-worker-1] INFO ROOT - Calculate factorial from 51 to 63\n13:07:33.123 [ForkJoinPool.commonPool-worker-2] INFO ROOT - Calculate factorial from 76 to 88\n13:07:33.123 [ForkJoinPool.commonPool-worker-3] INFO ROOT - Calculate factorial from 64 to 75\n13:07:33.163 [ForkJoinPool.commonPool-worker-3] INFO ROOT - New FactorialTask Created\n13:07:33.163 [main] INFO ROOT - Calculate factorial from 14 to 25\n13:07:33.163 [ForkJoinPool.commonPool-worker-3] INFO ROOT - New FactorialTask Created\n13:07:33.163 [ForkJoinPool.commonPool-worker-2] INFO ROOT - Calculate factorial from 89 to 100\n13:07:33.163 [ForkJoinPool.commonPool-worker-3] INFO ROOT - Calculate factorial from 26 to 38\n13:07:33.163 [ForkJoinPool.commonPool-worker-3] INFO ROOT - Calculate factorial from 39 to 50<\/pre>\n<p>Here you can see there are several tasks created, but only 3 worker threads &#8211; so these get picked up by the available threads in the pool.<\/p>\n<p>Also notice how the objects themselves are actually created in the main thread, before being passed to the pool for execution.<\/p>\n<p>This is actually a great way to explore and understand thread pools at runtime, with the help of a solid logging visualization tool <a href=\"https:\/\/stackify.com\/best-log-viewer-prefix\/\">such as Prefix<\/a>.<\/p>\n<p>The core aspect of logging from a thread pool is to make sure the thread name is easily identifiable in the log message; <a href=\"https:\/\/stackify.com\/log4j2-java\/\">Log4J2<\/a> is a great way to do that by making good use of layouts for example.<\/p>\n<h3><strong>Potential Risks of Using a Thread Pool<\/strong><\/h3>\n<p>Although thread pools provide significant advantages, you can also encounter several problems while using one, such as:<\/p>\n<ul>\n<li>using a thread pool that is too large or too small &#8211; if the thread pool contains too many threads, this can significantly affect the performance of the application; on the other hand, a thread pool that is too small may not bring the performance gain that you would expect<\/li>\n<li>deadlock can happen just like in any other multi-threading situation; for example, a task may be waiting for another task to complete, with no available threads for this latter one to execute; that&#8217;s why it&#8217;s usually a good idea to avoid dependencies between tasks<\/li>\n<li>queuing a very long task &#8211; to avoid blocking a thread for too long, you can specify a maximum wait time after which the task is rejected or re-added to the queue<\/li>\n<\/ul>\n<p>To mitigate these risks, you have to choose the thread pool type and parameters carefully, according to the tasks that they will handle. <a href=\"https:\/\/stackify.com\/ultimate-guide-performance-testing-and-software-testing\/\">Stress-testing<\/a> your system is also well-worth it to get some real-world data of how your thread pool behaves under load.<\/p>\n<h3><strong>Conclusion<\/strong><\/h3>\n<p>Thread pools provide a significant advantage by, simply put, separating the execution of tasks from the creation and management of threads. Additionally, when used right, they can greatly improve the performance of your application.<\/p>\n<p>And, the great thing about the Java ecosystem is that you have access to some of the most mature and battle-tested implementations of thread-pools out there if you learn to leverage them properly and take full advantage of them.<\/p>\n<p>Want to improve your Java applications? Try <a href=\"https:\/\/stackify.com\/retrace\">Stackify Retrace<\/a> for application performance and troubleshooting and <a href=\"https:\/\/stackify.com\/prefix\">Stackify Prefix<\/a> to write better code.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Thread pool\u00a0is a core concept in multithreaded programming which, simply put, represents a collection of idle threads that can be used to execute tasks. First, let&#8217;s outline a frame of reference for multithreading and why we may need to use a thread pool. A thread is an execution context that can run a set of [&hellip;]<\/p>\n","protected":false},"author":15,"featured_media":38228,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[7],"tags":[40,30],"class_list":["post-13398","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-developers","tag-java","tag-prefix"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v25.6) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Finally Getting the Most out of the Java Thread Pool - Stackify<\/title>\n<meta name=\"description\" content=\"Finally understanding how thread pools really work in Java can be the difference between your application being a slog, or a clean and efficient system.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/stackify.com\/java-thread-pools\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Finally Getting the Most out of the Java Thread Pool - Stackify\" \/>\n<meta property=\"og:description\" content=\"Finally understanding how thread pools really work in Java can be the difference between your application being a slog, or a clean and efficient system.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/stackify.com\/java-thread-pools\/\" \/>\n<meta property=\"og:site_name\" content=\"Stackify\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/Stackify\/\" \/>\n<meta property=\"article:published_time\" content=\"2017-09-06T14:26:59+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-07-02T12:11:48+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/stackify.com\/wp-content\/uploads\/2017\/09\/The-Challenge-of-Java-Thread-Pools-881x441-1.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"881\" \/>\n\t<meta property=\"og:image:height\" content=\"441\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Eugen Paraschiv\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@stackify\" \/>\n<meta name=\"twitter:site\" content=\"@stackify\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Eugen Paraschiv\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/stackify.com\/java-thread-pools\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/stackify.com\/java-thread-pools\/\"},\"author\":{\"name\":\"Eugen Paraschiv\",\"@id\":\"https:\/\/stackify.com\/#\/schema\/person\/e372b6a6f64edbedafad33027d518482\"},\"headline\":\"Finally Getting the Most out of the Java Thread Pool\",\"datePublished\":\"2017-09-06T14:26:59+00:00\",\"dateModified\":\"2024-07-02T12:11:48+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/stackify.com\/java-thread-pools\/\"},\"wordCount\":2215,\"publisher\":{\"@id\":\"https:\/\/stackify.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/stackify.com\/java-thread-pools\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/stackify.com\/wp-content\/uploads\/2017\/09\/The-Challenge-of-Java-Thread-Pools-881x441-1.jpg\",\"keywords\":[\"Java\",\"Prefix\"],\"articleSection\":[\"Developer Tips, Tricks &amp; Resources\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/stackify.com\/java-thread-pools\/\",\"url\":\"https:\/\/stackify.com\/java-thread-pools\/\",\"name\":\"Finally Getting the Most out of the Java Thread Pool - Stackify\",\"isPartOf\":{\"@id\":\"https:\/\/stackify.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/stackify.com\/java-thread-pools\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/stackify.com\/java-thread-pools\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/stackify.com\/wp-content\/uploads\/2017\/09\/The-Challenge-of-Java-Thread-Pools-881x441-1.jpg\",\"datePublished\":\"2017-09-06T14:26:59+00:00\",\"dateModified\":\"2024-07-02T12:11:48+00:00\",\"description\":\"Finally understanding how thread pools really work in Java can be the difference between your application being a slog, or a clean and efficient system.\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/stackify.com\/java-thread-pools\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/stackify.com\/java-thread-pools\/#primaryimage\",\"url\":\"https:\/\/stackify.com\/wp-content\/uploads\/2017\/09\/The-Challenge-of-Java-Thread-Pools-881x441-1.jpg\",\"contentUrl\":\"https:\/\/stackify.com\/wp-content\/uploads\/2017\/09\/The-Challenge-of-Java-Thread-Pools-881x441-1.jpg\",\"width\":881,\"height\":441},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/stackify.com\/#website\",\"url\":\"https:\/\/stackify.com\/\",\"name\":\"Stackify\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/stackify.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/stackify.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/stackify.com\/#organization\",\"name\":\"Stackify\",\"url\":\"https:\/\/stackify.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/stackify.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/stackify.com\/wp-content\/uploads\/2024\/05\/logo-1.png\",\"contentUrl\":\"https:\/\/stackify.com\/wp-content\/uploads\/2024\/05\/logo-1.png\",\"width\":1377,\"height\":430,\"caption\":\"Stackify\"},\"image\":{\"@id\":\"https:\/\/stackify.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/Stackify\/\",\"https:\/\/x.com\/stackify\",\"https:\/\/www.instagram.com\/stackify\/\",\"https:\/\/www.linkedin.com\/company\/2596184\",\"https:\/\/www.youtube.com\/stackify\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/stackify.com\/#\/schema\/person\/e372b6a6f64edbedafad33027d518482\",\"name\":\"Eugen Paraschiv\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/stackify.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/0c0bb39bd24aea78b56c6516a3e7dcab?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/0c0bb39bd24aea78b56c6516a3e7dcab?s=96&d=mm&r=g\",\"caption\":\"Eugen Paraschiv\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Finally Getting the Most out of the Java Thread Pool - Stackify","description":"Finally understanding how thread pools really work in Java can be the difference between your application being a slog, or a clean and efficient system.","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:\/\/stackify.com\/java-thread-pools\/","og_locale":"en_US","og_type":"article","og_title":"Finally Getting the Most out of the Java Thread Pool - Stackify","og_description":"Finally understanding how thread pools really work in Java can be the difference between your application being a slog, or a clean and efficient system.","og_url":"https:\/\/stackify.com\/java-thread-pools\/","og_site_name":"Stackify","article_publisher":"https:\/\/www.facebook.com\/Stackify\/","article_published_time":"2017-09-06T14:26:59+00:00","article_modified_time":"2024-07-02T12:11:48+00:00","og_image":[{"width":881,"height":441,"url":"https:\/\/stackify.com\/wp-content\/uploads\/2017\/09\/The-Challenge-of-Java-Thread-Pools-881x441-1.jpg","type":"image\/jpeg"}],"author":"Eugen Paraschiv","twitter_card":"summary_large_image","twitter_creator":"@stackify","twitter_site":"@stackify","twitter_misc":{"Written by":"Eugen Paraschiv","Est. reading time":"10 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/stackify.com\/java-thread-pools\/#article","isPartOf":{"@id":"https:\/\/stackify.com\/java-thread-pools\/"},"author":{"name":"Eugen Paraschiv","@id":"https:\/\/stackify.com\/#\/schema\/person\/e372b6a6f64edbedafad33027d518482"},"headline":"Finally Getting the Most out of the Java Thread Pool","datePublished":"2017-09-06T14:26:59+00:00","dateModified":"2024-07-02T12:11:48+00:00","mainEntityOfPage":{"@id":"https:\/\/stackify.com\/java-thread-pools\/"},"wordCount":2215,"publisher":{"@id":"https:\/\/stackify.com\/#organization"},"image":{"@id":"https:\/\/stackify.com\/java-thread-pools\/#primaryimage"},"thumbnailUrl":"https:\/\/stackify.com\/wp-content\/uploads\/2017\/09\/The-Challenge-of-Java-Thread-Pools-881x441-1.jpg","keywords":["Java","Prefix"],"articleSection":["Developer Tips, Tricks &amp; Resources"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/stackify.com\/java-thread-pools\/","url":"https:\/\/stackify.com\/java-thread-pools\/","name":"Finally Getting the Most out of the Java Thread Pool - Stackify","isPartOf":{"@id":"https:\/\/stackify.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/stackify.com\/java-thread-pools\/#primaryimage"},"image":{"@id":"https:\/\/stackify.com\/java-thread-pools\/#primaryimage"},"thumbnailUrl":"https:\/\/stackify.com\/wp-content\/uploads\/2017\/09\/The-Challenge-of-Java-Thread-Pools-881x441-1.jpg","datePublished":"2017-09-06T14:26:59+00:00","dateModified":"2024-07-02T12:11:48+00:00","description":"Finally understanding how thread pools really work in Java can be the difference between your application being a slog, or a clean and efficient system.","inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/stackify.com\/java-thread-pools\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/stackify.com\/java-thread-pools\/#primaryimage","url":"https:\/\/stackify.com\/wp-content\/uploads\/2017\/09\/The-Challenge-of-Java-Thread-Pools-881x441-1.jpg","contentUrl":"https:\/\/stackify.com\/wp-content\/uploads\/2017\/09\/The-Challenge-of-Java-Thread-Pools-881x441-1.jpg","width":881,"height":441},{"@type":"WebSite","@id":"https:\/\/stackify.com\/#website","url":"https:\/\/stackify.com\/","name":"Stackify","description":"","publisher":{"@id":"https:\/\/stackify.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/stackify.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/stackify.com\/#organization","name":"Stackify","url":"https:\/\/stackify.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/stackify.com\/#\/schema\/logo\/image\/","url":"https:\/\/stackify.com\/wp-content\/uploads\/2024\/05\/logo-1.png","contentUrl":"https:\/\/stackify.com\/wp-content\/uploads\/2024\/05\/logo-1.png","width":1377,"height":430,"caption":"Stackify"},"image":{"@id":"https:\/\/stackify.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/Stackify\/","https:\/\/x.com\/stackify","https:\/\/www.instagram.com\/stackify\/","https:\/\/www.linkedin.com\/company\/2596184","https:\/\/www.youtube.com\/stackify"]},{"@type":"Person","@id":"https:\/\/stackify.com\/#\/schema\/person\/e372b6a6f64edbedafad33027d518482","name":"Eugen Paraschiv","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/stackify.com\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/0c0bb39bd24aea78b56c6516a3e7dcab?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/0c0bb39bd24aea78b56c6516a3e7dcab?s=96&d=mm&r=g","caption":"Eugen Paraschiv"}}]}},"_links":{"self":[{"href":"https:\/\/stackify.com\/wp-json\/wp\/v2\/posts\/13398"}],"collection":[{"href":"https:\/\/stackify.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/stackify.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/stackify.com\/wp-json\/wp\/v2\/users\/15"}],"replies":[{"embeddable":true,"href":"https:\/\/stackify.com\/wp-json\/wp\/v2\/comments?post=13398"}],"version-history":[{"count":2,"href":"https:\/\/stackify.com\/wp-json\/wp\/v2\/posts\/13398\/revisions"}],"predecessor-version":[{"id":44443,"href":"https:\/\/stackify.com\/wp-json\/wp\/v2\/posts\/13398\/revisions\/44443"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/stackify.com\/wp-json\/wp\/v2\/media\/38228"}],"wp:attachment":[{"href":"https:\/\/stackify.com\/wp-json\/wp\/v2\/media?parent=13398"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/stackify.com\/wp-json\/wp\/v2\/categories?post=13398"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/stackify.com\/wp-json\/wp\/v2\/tags?post=13398"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}