转载:
http://www.javamex.com/tutorials/threads/ThreadPoolExecutor.shtml
/**
* Creates a new <tt>ThreadPoolExecutor</tt> with the given initial
* parameters and default rejected execution handler.
*
* @param corePoolSize the number of threads to keep in the
* pool, even if they are idle.
* @param maximumPoolSize the maximum number of threads to allow in the
* pool.
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
* @param unit the time unit for the keepAliveTime
* argument.
* @param workQueue the queue to use for holding tasks before they
* are executed. This queue will hold only the <tt>Runnable</tt>
* tasks submitted by the <tt>execute</tt> method.
* @param threadFactory the factory to use when the executor
* creates a new thread.
* @throws IllegalArgumentException if corePoolSize or
* keepAliveTime less than zero, or if maximumPoolSize less than or
* equal to zero, or if corePoolSize greater than maximumPoolSize.
* @throws NullPointerException if <tt>workQueue</tt>
* or <tt>threadFactory</tt> are null.
*/
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.
For example, the pattern of a simple server that used one threaded job to handle each incoming connection would look as follows. Note that there are some details here that for simplicity we have omitted— such as how the thread pool is shut down or what to do if it is "overloaded"— but we'll come to these issues in a moment:
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 the ThreadPoolExecutor 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 as newFixedThreadPool() in fact declare that they return an implementation of ExecutorService: an interface that ThreadPoolExecutor, 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 that ThreadPoolExecutor 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.
Controlling the queue with ThreadPoolExecutor
The previous page showed a skeleton of a simple server with ThreadPoolExecutor. We used a common paradigm, in which one thread continually sits waiting to accept connections; these connections are then each farmed off to be executed by the next available thread. Now, one problem that can occur is if we get a large volume of incoming connections so that the available threads can't proess them fast enough. In this case, the connections waiting to be processed will be queued. But we haven't put any bounds on the queue, so that in the worst case, they will just continue to "pile up". If connections aren't being processed fast enough because the server is overloaded or "has a problem", then we're not going to help matters by piling up an endless number of connections that the server doesn't have a realistic chance of processing. At some point, we need to accept that "the server is busy" and drop further connections until things have calmed down.
To achieve this goal, we need to:
use a queue with a some maximum capacity;
handle rejected execution: add a piece of code to deal with what happens when an incoming job won't fit in the queue.
Specifying a queue with maximum capacity
In our initial example, for convenience, we just used the Executors helper class to construct a thread pool with default options. However, if we constract a ThreadPoolExecutor object directly via its constructor, we can specify various additional parameters including the implementation of BlockingQueue that we wish to use as the job queue. In this case, we can use an ArrayBlockingQueue or LinkedBlockingQueue with a maximum capacity. The queue is declared to take objects of type Runnable, since this is what the thread pool deals with:
BlockingQueue q = new ArrayBlockingQueue(20);
ThreadPoolExecutor ex = new ThreadPoolExecutor(4, 10, 20, TimeUnit.SECONDS, q);
Note a side effect of specifying our own queue is that we must specify the maximum number of threads (10 in this case) and the time-to-live of idle threads (20 seconds in this case). As the number of simultaneous connections grows, the thread pool will automatically expand the number of threads up to this maximum. When the number of connections (and hence threads needed) decreases, the thread pool will "kill" each spare thread after it has been sitting idle for 20 seconds, until we're down to our "core" size of 4 threads (the first parameter).
If you specify your own job queue, be careful not to post jobs "manually" to the queue (using the regular queue methods). If you do so, the job will not be picked up by the thread pool. Always use ThreadPoolExecutor.execute() even though it's "your own queue".
Rejected execution handlers and RejectedExecutionException
With an upper bound on our queue size, the other issue we need to deal with is what happens if a job isn't executed because the queue is full. In this case, we'll be left with a "dangling" socket that we should close as soon as possible. By default, we can handle the full queue situation by catching RejectedExecutionException:
while (!shutDownRequested()) {
Socket s = null;
try {
s = ss.accept();
exec.execute(new ConnectionRunnable(s));
} catch (RejectedExecutionException rej) {
try { s.close(); } catch (Exception ignore) {}
} catch (Exception e) {
// ... log
}
}
Another way to handle closing the socket is to pass a RejectedExecutionHandler into the constructor of our ThreadPoolExecutor. RejectedExecutionHandler is an interface that specifies one method that we must define:
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
...
}
Then, instead of throwing an exception, if the connection job won't fit on the queue, the ThreadPoolExecutor will call our rejectedExecution() method instead. Whether you catch the exception or define a separate handler essentially depends on which makes your design easier— for example, you could have a single rejection handler shared by multiple executors.
分享到:
相关推荐
Java 线程池例子 ThreadPoolExecutor Java 中的线程池是指一个容器,里面包含了多个线程,这些线程可以重复使用,以避免频繁创建和销毁线程的开销。ThreadPoolExecutor 是 Java 中一个非常重要的线程池实现类,它...
《ThreadPoolExecutor源码解析》 ThreadPoolExecutor是Java并发编程中重要的组件,它是ExecutorService接口的实现,用于管理和调度线程的执行。理解其源码有助于我们更好地控制并发环境下的任务执行,提高系统的...
线程池是多线程编程中一种高效管理线程资源的方式,主要由Java的`ThreadPoolExecutor`类实现。线程池的工作机制在于控制线程数量,它会将任务放入队列,然后根据线程池的设定创建并启动线程执行这些任务。如果线程...
ThreadPoolExecutor的使用和Android常见的4种线程池使用介绍
"JDK1.5中的线程池(java.util.concurrent.ThreadPoolExecutor)使用" JDK1.5中的线程池(java.util.concurrent.ThreadPoolExecutor)使用是Java多线程编程中的一种重要概念。随着多线程编程的普及,线程池的使用变得...
ThreadPoolExecutor线程池 ThreadPoolExecutor线程池是Java并发编程中的一种线程管理机制,它允许开发者控制线程池的大小、线程的创建和销毁、任务的执行和队列管理等。通过ThreadPoolExecutor,可以实现线程池的...
(转)线程池:java_util_ThreadPoolExecutor 比较详细的介绍了ThreadPoolExecutor用法与属性
ThreadPoolExecutor源码解析.md
1.资源简介:PyQt5中使用多线程模块QThread解决了PyQt5界面程序执行比较耗时操作时,程序卡顿出现的无响应以及界面输出无法实时显示的问题,采用线程池ThreadPoolExecutor解决了ping多个IP多任务耗时问题。...
ThreadPoolExecutor使用和思考
JDK1[1].5中的线程池(ThreadPoolExecutor)使用简介
线程池原理-ThreadPoolExecutor源码解析 1.构造方法及参数 2.阻塞对列: BlockingQueue 3.线程工厂: DefaultThreadFactory 4.拒绝策略: RejectedExecutionHandler 5.执行线程 Executor
### ThreadPoolExecutor 运转机制详解 #### 一、ThreadPoolExecutor 的基本概念与构造函数解析 在Java并发编程中,`ThreadPoolExecutor` 是一种强大的工具,它可以帮助开发者有效地管理和执行线程。`...
线程池ThreadPoolExecutor实战及其原理分析(下)线程池ThreadPoolExecutor实战及其原理分析(下)线程池ThreadPoolExecutor实战及其原理分析(下)线程池ThreadPoolExecutor实战及其原理分析(下)线程池ThreadPoolExecutor...
内容概要:本篇文章深入探讨了Java中多线程管理的一个关键组件——ThreadPoolExecutor的工作机制及其优化策略。主要涵盖ThreadPoolExecutor的基础概念介绍,创建配置参数的意义与选择方法,以及在实际编程中的几种...
在IT行业中,Redis和Java的ThreadPoolExecutor是两个非常重要的工具,它们在处理高并发和任务调度方面发挥着关键作用。Redis是一种高效的键值存储系统,常用于缓存、消息队列等场景。而ThreadPoolExecutor是Java并发...
在《阿里巴巴java开发手册》中...另外由于前面几种方法内部也是通过ThreadPoolExecutor方式实现,使用ThreadPoolExecutor有助于大家明确线程池的运行规则,创建符合自己的业务场景需要的线程池,避免资源耗尽的风险。
《JDK之ThreadPoolExecutor源码分析1》 在Java编程中,线程池是一种高效的管理线程的方式,它通过复用已存在的线程来避免频繁创建和销毁线程带来的开销。ThreadPoolExecutor作为Java中的线程池实现,其内部机制相当...
线程池通过ThreadPoolExecutor类实现,这是一个高度可配置的工具,能够根据具体需求定制线程的创建、管理和销毁策略。 ThreadPoolExecutor的核心参数包括: 1. corePoolSize:核心线程数,这是线程池在非繁忙状态下...
ThreadPoolExecutor是Java并发编程中非常重要的一个组件,它位于`java.util.concurrent`包下,用于管理线程资源,实现线程池服务。线程池通过有效地控制并发执行的任务数量,可以提高系统的性能和稳定性。 ...