在Java中,如果只是需要一个简单的thread pool,ExecuteService可能更为合适,这是一个Interface。可以通过调用Executor的静态方法来获得一些简单的threadpool,如:
- ExecuteService pool = Executors.newFixedThreadPool(poolSize);
但如果要用定制的thread pool,则要使用ThreadPoolExecutor类,这是一个高度可定制的线程池类,下面是一些重要的参数和方法:
首先是构造函数。以最简单的构造函数为例:
public ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue)
public ThreadPoolExecutor( int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue)
看起来挺复杂的。这里介绍一下。
corePoolSize 指的是保留的线程池大小。
maximumPoolSize 指的是线程池的最大大小。
keepAliveTime 指的是空闲线程结束的超时时间。
unit 是一个枚举,表示 keepAliveTime 的单位。
workQueue 表示存放任务的队列。
我们可以从线程池的工作过程中了解这些参数的意义。线程池的工作过程如下:
1、线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面有任务,线程池也不会马上执行它们。
2、当调用 execute() 方法添加一个任务时,线程池会做如下判断:
a. 如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;
b. 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列。
c. 如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要创建线程运行这个任务;
d. 如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池会抛出异常,告诉调用者“我不能再接受任务了”。
3、当一个线程完成任务时,它会从队列中取下一个任务来执行。
4、当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运行的线程数大于 corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它最终会收缩到 corePoolSize 的大小。
这样的过程说明,并不是先加入任务就一定会先执行。假设队列大小为 10,corePoolSize 为 3,maximumPoolSize 为 6,那么当加入 20 个任务时,执行的顺序就是这样的:首先执行任务 1、2、3,然后任务 4~13 被放入队列。这时候队列满了,任务 14、15、16 会被马上执行,而任务 17~20 则会抛出异常。最终顺序是:1、2、3、14、15、16、4、5、6、7、8、9、10、11、12、13。下面是一个线程池使用的例子:
public static void main(String[] args) {
BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 5, 1000,TimeUnit.SECONDS, queue);
for (int i = 0; i < 20; i++) {
final int no = i;
executor.execute(new Runnable() {
public void run() {
System.out.println(no + "==================");
}
});
}
executor.shutdown();
}
对这个例子的说明如下:
1、BlockingQueue 只是一个接口,常用的实现类有 LinkedBlockingQueue 和 ArrayBlockingQueue。用 LinkedBlockingQueue 的好处在于没有大小限制。这样的话,因为队列不会满,所以 execute() 不会抛出异常,而线程池中运行的线程数也永远不会超过 corePoolSize 个,keepAliveTime 参数也就没有意义了。
2、shutdown() 方法不会阻塞。调用 shutdown() 方法之后,主线程就马上结束了,而线程池会继续运行直到所有任务执行完才会停止。如果不调用 shutdown() 方法,那么线程池会一直保持下去,以便随时添加新的任务。
到这里对于这个线程池还只是介绍了一小部分。ThreadPoolExecutor 具有很强的可扩展性,不过扩展它的前提是要熟悉它的工作方式。
java.util.concurrent.ThreadPoolExecutor 类提供了丰富的可扩展性。你可以通过创建它的子类来自定义它的行为。例如,我希望当每个任务结束之后打印一条消息,但我又无法修改任务对象,那么我可以这样写:
[java]
ThreadPoolExecutor executor = new ThreadPoolExecutor(size, maxSize, 1, TimeUnit.DAYS, queue) {
@Override
protected void afterExecute(Runnable r, Throwable t) {
System.out.println("Task finished.");
}
};<span style="font-family: Arial; text-indent: 2em;"> </span>
除了 afterExecute 方法之外,ThreadPoolExecutor 类还有 beforeExecute() 和 terminated() 方法可以重写,分别是在任务执行之前和整个线程池停止之后执行。
除了可以添加任务执行前后的动作之外, ThreadPoolExecutor 还允许你自定义当添加任务失败后的执行策略。你可以调用线程池的 setRejectedExecutionHandler() 方法,用自定义的 RejectedExecutionHandler 对象替换现有的策略。 ThreadPoolExecutor 提供 4 个现有的策略,分别是:
ThreadPoolExecutor.AbortPolicy:表示拒绝任务并抛出异常
ThreadPoolExecutor.DiscardPolicy:表示拒绝任务但不做任何动作
ThreadPoolExecutor.CallerRunsPolicy:表示拒绝任务,并在调用者的线程中直接执行该任务
ThreadPoolExecutor.DiscardOldestPolicy:表示先丢弃任务队列中的第一个任务,然后把这个任务加进队列。
这里是一个例子:
[java]
ThreadPoolExecutor executor = new ThreadPoolExecutor(size, maxSize, 1, TimeUnit.DAYS, queue);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
除此之外,你也可以通过实现 RejectedExecutionHandler 接口来编写自己的策略。下面是一个例子:
[java]
ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 6, 1, TimeUnit.SECONDS, queue,
new RejectedExecutionHandler() {
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.out.println(String.format("Task %d rejected.", r.hashCode()));
}
}
);
相关推荐
主要介绍了java ThreadPoolExecutor使用方法简单介绍的相关资料,需要的朋友可以参考下
java ThreadPoolExecutor 并发调用实例详解 java 中的并发编程是指在多个线程中执行多个任务,以提高程序的执行效率。在 Java 中,有多种方式可以实现并发编程,包括使用 Thread、Runnable、Callable、Future、...
Java 线程池例子 ThreadPoolExecutor Java 中的线程池是指一个容器,里面包含了多个线程,这些线程可以重复使用,以避免频繁创建和销毁线程的开销。ThreadPoolExecutor 是 Java 中一个非常重要的线程池实现类,它...
(转)线程池:java_util_ThreadPoolExecutor 比较详细的介绍了ThreadPoolExecutor用法与属性
提供工厂方法来创建不同类型的线程池,这篇文章主要介绍了Java ThreadPoolExecutor 线程池的使用介绍,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来...
ThreadPoolExecutor使用和思考
Java ThreadPoolExecutor参数深入理解 Java ThreadPoolExecutor是Java并发编程中一个非常重要的组件,它提供了一种灵活的方式来管理线程池。ThreadPoolExecutor的参数深入理解是Java开发人员需要掌握的重要知识点,...
在《阿里巴巴java开发手册》中指出了线程资源必须通过线程池提供,不允许在应用中自行显示的创建线程,这样一方面是线程的创建更加规范,可以合理控制开辟线程的数量;另一方面线程的细节管理交给线程池处理,优化了...
"JDK1.5中的线程池(java.util.concurrent.ThreadPoolExecutor)使用" JDK1.5中的线程池(java.util.concurrent.ThreadPoolExecutor)使用是Java多线程编程中的一种重要概念。随着多线程编程的普及,线程池的使用变得...
Java线程池是Java并发编程中...总结来说,理解并正确使用Java线程池和ThreadPoolExecutor对于优化Java应用程序的并发性能至关重要。通过调整线程池的参数,可以平衡资源利用率和系统响应时间,从而提高整体的系统效率。
主要介绍了java中Executor,ExecutorService,ThreadPoolExecutor详解的相关资料,需要的朋友可以参考下
"java 中ThreadPoolExecutor 原理分析" ThreadPoolExecutor 是 Java 并发编程中的一种高级线程池实现,它提供了一个灵活的线程池管理机制,允许开发者根据需要配置线程池的参数以满足不同的需求。在这篇文章中,...
java线程池使用后到底要关闭吗 java线程池是一种高效的并发编程技术,可以帮助开发者更好地管理线程资源,提高系统的性能和可靠性。然而,在使用java线程池时,一个常见的问题是:使用完线程池后到底要不要关闭?...
Java线程池ThreadPoolExecutor原理及使用实例 Java线程池ThreadPoolExecutor是Java并发编程中的一种基本机制,主要用于管理和执行任务的线程池。下面对其原理和使用实例进行详细介绍。 线程池概述 线程池是一个...
Java多线程实现数据切割批量执行,实现限流操作。 java线程池Executors实现数据批量操作。 批量异步Executors处理数据,实现限流操作,QPS限流。 线程池调用第三方接口限流实现逻辑。 案例适合: 1.批量处理大数据。...
Java 中 ThreadPoolExecutor 常识汇总 ThreadPoolExecutor 是 Java 中的一种线程池实现,用于管理线程池中的线程,提高系统的并发处理能力。在 Java 中,线程池技术广泛应用于并发编程中,通过调用 ...
ThreadPoolExecutor源码解析.md
ThreadPoolExecutor是Java并发编程中重要的组件,它是ExecutorService接口的实现,用于管理和调度线程的执行。理解其源码有助于我们更好地控制并发环境下的任务执行,提高系统的效率和稳定性。 1. **线程池状态** ...
Java提供了多种线程池实现,包括ThreadPoolExecutor、ScheduledThreadPoolExecutor等。 七、并发编程的优点和挑战 并发编程可以提高系统的性能、可扩展性和灵活性,但是也存在一些挑战,例如线程安全、死锁、饥饿...