Significance of Thread Pools
Thread Pools use worker threads to minimize thread creation overhead. Thread Pools reduce the memory management overhead which is important for large scale applications. Thread Pools allow the applications to degrade gracefully.Executor Service Objects
Java supports executor framework which provide the enablers for thread creation and management. Listed are some of the Java objects of executor service and their key purpose.Executor
Executor interface provides a way to decouple tasks from how a task will run, thread to use etc. Executor is normally used instead of creating threads.ExecutorService
ExecutorService interface represents an asynchronous execution mechanism which is capable of executing tasks in the background.ThreadPoolExecutor
ExecutorService is an interface and ThreadPoolExecutor is one of the concrete implementations of ExecutorService. Executes submitted tasks using one of the several pooled threads. ThreadPoolExecutor provides many adjustable parameters and hooks. For ease of programming it is recommended to use the static factory methods provided by Executors.Executors
Provides factory and utility methods for executor. They provide static methods like newFixedThreadPool(), newCachedThreadPool() which are much easier to use.Approaches for Thread Pools
Java supports several approaches for handling thread pools. These include:Fixed thread pool
This approach reuses fixed number of threads. At any point at-most "n" threads would be active. If additional tasks are submitted when all threads are active the tasks would be queued. Threads in the pool will exist until it is explicitly shutdown.Cached thread pool
This approach creates new threads as needed, but will reuse previously constructed threads when they are available. If no threads are available for a task a new thread will be created and added to the pool. Threads that are not used for 60 secs will be terminated and removed from the cache.Single thread pool
This approach uses a single worker thread. Tasks submitted would be executed sequentially. This can be assumed equivalent to a fixed thread pool of size "1". The primary difference is that fixed thread pool can reconfigured to use additional threads but single thread pool is not re-configurable.Example of Thread Pool usage
This example shows usage of fixed, cached and single thread pool.package com.sourcetricks.threadpool; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class ThreadPool { class MyThread extends Thread { private int id; public MyThread(int id) { this.id = id; } public void run() { System.out.println("Starting thread " + id); doSomeWork(); System.out.println("Completed thread " + id); } private void doSomeWork() { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } } // Not using thread pool private void doWithoutThreadPool() { for ( int i = 0; i < 20; i++ ) { MyThread thread = new MyThread(i); thread.start(); } } // Using fixed thread pool private void doWithFixedThreadPool1() throws InterruptedException { ExecutorService executor = Executors.newFixedThreadPool(5); for ( int i = 0; i < 20; i++ ) { MyThread thread = new MyThread(i); executor.execute(thread); } System.out.println("Active thread count = " + ((ThreadPoolExecutor)executor).getActiveCount()); // Don't accept new work executor.shutdown(); // Wait for 30 secs for the threads to complete executor.awaitTermination(30, TimeUnit.SECONDS); } // Using fixed thread pool. Directly uses the ThreadPoolEexcutor // which provides finer control private void doWithFixedThreadPool2() throws InterruptedException { int core = 5; int max = 10; int keepalive = 5000; ExecutorService executor = new ThreadPoolExecutor( core, max, keepalive, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); for ( int i = 0; i < 20; i++ ) { MyThread thread = new MyThread(i); executor.execute(thread); } System.out.println("Active thread count = " + ((ThreadPoolExecutor)executor).getActiveCount()); executor.shutdown(); executor.awaitTermination(30, TimeUnit.SECONDS); } // Using cached thread pool private void doWithCachedThreadPool() throws InterruptedException { ExecutorService executor = Executors.newCachedThreadPool(); for ( int i = 0; i < 20; i++ ) { MyThread thread = new MyThread(i); executor.execute(thread); } System.out.println("Active thread count = " + ((ThreadPoolExecutor)executor).getActiveCount()); } // Using single thread pool private void doWithSingleThreadPool() throws InterruptedException { ExecutorService executor = Executors.newSingleThreadExecutor(); // Executor returned is not reconfigurable for ( int i = 0; i < 20; i++ ) { MyThread thread = new MyThread(i); executor.execute(thread); } } public static void main(String[] args) { ThreadPool threadPool = new ThreadPool(); try { threadPool.doWithCachedThreadPool(); } catch (InterruptedException e) { e.printStackTrace(); } } }
0 comments:
Post a Comment