java中线程池的使用(ThreadPoolExecutor)

简介:

一.为什么使用线程池:

1.降低资源消耗。主要指的是降低创建和销毁线程时产生的cpu资源消耗,线程池通过持续工作的线程执行不断分配的新任务,来减少频繁的线程创建与销毁。

##2.提高响应速度。同上
##3.提高线程的可管理性。线程是稀缺资源,频繁的创建销毁,以及没有控制的大量创建,都会影响系统的稳定性。使用线程池可以统一分配,调优,监控资源。

二.如何创建线程池:

new ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory,RejectedExecutionHandler handler);

corePoolSize:

线程池的基本大小,即在没有任务需要执行的时候线程池中运行的线程数量。只有在工作队列满了的情况下才会创建超出这个数量的线程。

相关1:

刚刚创建ThreadPoolExecutor的时候,线程并不会 立即启动,而是要等到有任务提交时才会启动。如果预先调用了prestartCoreThread()/prestartAllCoreThreads(),则会事先启动核心线程。

相关2:

考虑到keepAliveTime()和allowCoreThreadTimeOut()超市参数的影响,没有任务或者没有足够任务执行的时候,线程池中运行线程的数量(线程池的大小)小于等于corePoolSize。

maximumPoolSize:

线程池中允许的最大线程数,线程池中的当前运行线程数不会超过这个值,为了保证系统资源有控制的消耗。

相关1:

由于maximumPoolSize可以在运行中通过setMaximumPoolSize()来设置,所以可以通过largestPoolSize()方法来获得线程池曾经运行过的最大线程数量,来评估当前maximumPoolSize设置是否合适。

keepAliveTime:

当线程空闲后,保留的时间。用来在任务不繁忙的时候减少运行线程数量。在单任务时间较短,任务请求较频繁的情况下,可以适当延长保留存活时间来减少系统创建和销毁线程的开销。

相关1:

对于核心线程,默认一直保留存活,如果将allowCoreThreadTimeOut设置为true,则核心线程也接受keepAliveTime的约束。

TimeUnit unit:

用来修饰keepAliveTime的时间单位,可以为纳秒,毫秒,秒,分,小时,天等TimeUnit中的静态常量。

BlockingQueue:

线程安全的队列,用来存放排队的任务。

相关1:

此BlockingQueue的实现有:
->ArrayBlockingQueue:基于数组结构的有届阻塞队列,FIFO
->LinkedBlockingQueue:基于链表的阻塞队列,FIFO。吞吐量大于上者。静态工厂方法Executors.newFixedThreadPool()使用了这个队列
->SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量高于LinkedBlockingQueue.静态工厂方法Executors.newCachedThreadPool()使用了这个队列。
->PriorityBlockingQueue:一个具有优先级的无限阻塞队列。

ThreadFactory:

用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字。

RejectedExecutionHandler:

当队列和线程池都满了之后的饱和策略。默认情况下是AbortPolicy,表示无法处理新任务时抛出异常。以下是JDK1.5提供的四种策略:
->AbortPolicy:直接抛出异常
->CallerRunsPolicy:只用调用者所在的线程来运行任务。
->DiscardOldestPolicy:丢弃队列里最近一个任务,并执行当前任务。
->DiscardPolicy:不处理,丢弃掉。
->也可以根据应用场景需要来实现RejectedExecutionHandler接口自定义策略。如记录日志或持久化不能处理的任务。

三.如何调用线程池:

1.通过execute(Runnable run)方法来执行任务:

threadsPool.execute(new Runnable(){

@override
public void run(){
    //code to run.
}

});
但是execute()方法没有返回值,无法获得任务执行的情况信息。

2.通过submit()方法来提交执行任务:

Future future=executor.submit(harReturnValueTask);
try{

Object o=future.get();

}catch(Exeception e){

}finally{

executor.shutdown();

}
submit()方法会返回一个future对象,通过future的get()方法,可以获得任务执行情况。get()方法会阻塞直到任务执行完毕。也可以使用get(long timeout, TimeUnit unit)来设置最长阻塞时间。

如何关闭线程池:

我们可以通过调用线程池的shutdown或shutdownNow方法来关闭线程池,它们的原理是遍历线程池中的工作线程,然后逐个调用线程的interrupt方法来中断线程,所以无法响应中断的任务可能永远无法终止。但是它们存在一定的区别,shutdownNow首先将线程池的状态设置成STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表,而shutdown只是将线程池的状态设置成SHUTDOWN状态,然后中断所有没有正在执行任务的线程。
只要调用了这两个关闭方法的其中一个,isShutdown方法就会返回true。当所有的任务都已关闭后,才表示线程池关闭成功,这时调用isTerminaed方法会返回true。至于我们应该调用哪一种方法来关闭线程池,应该由提交到线程池的任务特性决定,通常调用shutdown来关闭线程池,如果任务不一定要执行完,则可以调用shutdownNow。

今天困了,先写到这里,主要参考文章:
http://blog.csdn.net/scboyhj__/article/details/48805881

相关文章
|
3天前
|
存储 安全 Java
Java面试题:请解释Java内存模型(JMM)是什么,它如何保证线程安全?
Java面试题:请解释Java内存模型(JMM)是什么,它如何保证线程安全?
34 13
|
2天前
|
缓存 安全 Java
Java中线程池如何管理?
【7月更文挑战第11天】Java中线程池如何管理?
8 2
|
2天前
|
安全 算法 Java
Java中线程安全怎么做?
【7月更文挑战第11天】Java中线程安全怎么做?
9 2
|
2天前
|
存储 安全 算法
深入理解Java并发编程:线程安全与性能优化
【5月更文挑战第72天】 在现代软件开发中,尤其是Java应用开发领域,并发编程是一个无法回避的重要话题。随着多核处理器的普及,合理利用并发机制对于提高软件性能、响应速度和资源利用率具有重要意义。本文旨在探讨Java并发编程的核心概念、线程安全的策略以及性能优化技巧,帮助开发者构建高效且可靠的并发应用。通过实例分析和理论阐述,我们将揭示在高并发环境下如何平衡线程安全与系统性能之间的关系,并提出一系列最佳实践方法。
|
2天前
|
Java 调度
Java线程的六种状态
Java线程有六种状态: 初始(NEW)、运行(RUNNABLE)、阻塞(BLOCKED)、等待(WAITING)、超时等待(TIMED_WAITING)、终止(TERMINATED)。
13 1
|
3天前
|
监控 Java 调度
Java面试题:描述Java线程池的概念、用途及常见的线程池类型。介绍一下Java中的线程池有哪些优缺点
Java面试题:描述Java线程池的概念、用途及常见的线程池类型。介绍一下Java中的线程池有哪些优缺点
18 1
|
1天前
|
Java 调度
java中线程的6种状态
java中线程的6种状态
|
1天前
|
算法 Java 开发者
Java中的多线程编程技巧与实践
在现代软件开发中,多线程编程成为提升应用程序性能和响应能力的关键技术之一。本文将深入探讨Java语言中多线程编程的基础概念、常见问题及其解决方案,帮助开发者更好地理解和应用多线程技术。 【7月更文挑战第12天】
6 0
|
3天前
|
Java 调度
Java面试题:简述Java线程的生命周期及其状态转换。
Java面试题:简述Java线程的生命周期及其状态转换。
8 0
|
2月前
|
Java 调度
Java并发编程:深入理解线程池的原理与实践
【4月更文挑战第6天】本文将深入探讨Java并发编程中的重要概念——线程池。我们将从线程池的基本原理入手,逐步解析其工作过程,以及如何在实际开发中合理使用线程池以提高程序性能。同时,我们还将关注线程池的一些高级特性,如自定义线程工厂、拒绝策略等,以帮助读者更好地掌握线程池的使用技巧。