ThreadPoolExecutor
Introduced in Java 5, the ThreadPoolExecutor class provides a fairly flexible implementation of a Java thread pool as outlined in our introduction. In the simplest case, the class is used as follows:- we construct an instance of ThreadPoolExecutor somewhere fairly "early on" in our program's life cycle (e.g. when our server starts up), passing in parameters such as the numbe of threads;
- when we need a job executing in another thread, we call the ThreadPoolExecutor's execute() method, passing in the Runnable which is the task to be executed.
import java.util.concurrent.*; ... ExecutorService exec = Executors.newFixedThreadPool(4); private void runServer() { ServerSocket sock = new ServerSocket(portNo); while (!stopRequested) { Socket s = sock.accept(); exec.execute(new ConnectionRunnable(s)); } } private static class ConnectionRunnable implements Runnable { private final Socket s; ConnectionRunnable(Socket s) { this.s = s; } public void run() { // handle connection } }
Constructing a ThreadPoolExecutor: the Executors helper class
In the first line, exec will in practice be a ThreadPoolExecutor or some subclass thereof. We could have called theThreadPoolExecutor constructor directly, but it has a number of parameters which can be a bit unwieldy in the simplest case. The Executors class is a placeholder for a number of static utility methods to facilitate construction and use of thread pools (and in principle, other types of executors— see below). Utility methods such asnewFixedThreadPool() in fact declare that they return an implementation of ExecutorService: an interface thatThreadPoolExecutor, and potentially other classes in the future, implements. So in practice, that is how we will refer to our thread pool. As you see, here we construct a thread pool that will always have exactly four threads, but we'll see thatThreadPoolExecutor and the Executors utility class are actually more versatile.Our simple server then sits in a loop in some "main" thread (which calls runServer(), continually waiting for connections. Each time a connection comes in, it is passed to the thread pool to be executed in another thread when one is free to take on the job. Meanwhile, the main thread can immediately get back to accepting further incoming connections. At some point in the near future, and in one of the threads managed by the ThreadPoolExecutor, the run() method of the passed-in ConnectionRunnable will be executed.
Next: ThreadPoolExecutor options
This example shows a very simple case of using a ThreadPoolExecutor with default options. In some cases, we will need to set a few more options to make the thread pool behave in the desired way:- we may need to specify the type of job queue used by the thread pool (e.g. so that we can put a limit on its capacity), and specify a rejected execution handler which will be called when a job is rejected because the queue is full.
No comments:
Post a Comment