java线程池初识
来源:互联网 发布:无线电静默 知乎 编辑:程序博客网 时间:2024/05/02 19:02
java线程池初识
概述
当有多个请求到服务器需要新建线程来执行任务时,如果为每个请求都新建线程的话,那么服务器资源开销比较大,因此使用一个容器来管理线程,当请求到来的时候就从容器中取出空闲线程来处理。线程池和数据库连接池很类似,都是为了解决频繁创建比较耗资源的对象。
在执行并发任务时,我们可以把任务传递给一个线程池,来替代为每个并发执行的任务都启动一个新的线程,只要池里有空闲的线程,任务就会分配一个线程执行。在线程池的内部,任务被插入一个阻塞队列(BlockingQueue),线程池里的线程会去取这个队列里的任务。
利用线程池有三个好处
1、降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗2、提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行3、提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控
java中创建线程池
使用ThreadPoolExecutor构造方法创建线程池
/** * * @param corePoolSize 线程池中的线程数 * @param maximumPoolSize 线程池中最大线程数 * @param keepAliveTime 线程活动保持时间,线程池的工作线程空闲后,保持存活的时间。 * @param unit 线程活动保持时间单位 * @param workQueue 任务队列,用于保存等待执行的任务的阻塞队列。有多种阻塞队列 * @param threadFactory 用于设置创建线程的工厂 * @param handler 饱和策略,当线程池和队列都满了,说明线程池处于饱和状态, * 那么必须采取一种策略处理提交的新任务。 * 这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常。 */public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { //省略代码}
BlockingQueue阻塞队列类型
1、ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。2、LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列3、SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。4、PriorityBlockingQueue:一个具有优先级得无限阻塞队列。
使用Executors工具类创建
可以通过调用Ececutors中的某个静态工厂方法来创建一个线程池(它们的内部实现原理都是相同的,仅仅是使用了不同的工作队列或线程池大小)。Executors就像Collections工具类那样提供了些静态方法方便操作而已。
public class Executors { //创建一个定长的线程池,每当提交一个任务就创建一个线程,直到达到池的最大长度,这时线程池会保持长度不在变化 public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); } // public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory); } //创建一个单线程化的executor,它只会创建唯一的工作者线程来执行任务 public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); } public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory)); } //创建一个可缓存的线程池,如果当前的线程池的长度超过了处理的需要时,它可以灵活的回收空闲的线程,当需求增加时,它可以灵活的添加新的线程,并不会对池的长度做任何限制 public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); } public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), threadFactory); } /** Cannot instantiate. */ private Executors() {}}
向线程池中提交任务
public static void main(String[] args) { BlockingQueue<Runnable> workQueue = new LinkedBlockingDeque<Runnable>();//任务队列 ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 3, 60, TimeUnit.SECONDS, workQueue);//线程池 threadPoolExecutor.execute(new Task1());//执行任务1 threadPoolExecutor.execute(new Task2());//执行任务2 threadPoolExecutor.shutdown();//关闭线程池}
线程关闭
可以通过调用线程池的shutdown或shutdownNow方法来关闭线程池,但是它们的实现原理不同,shutdown的原理是只是将线程池的状态设置成SHUTDOWN状态,然后中断所有没有正在执行任务的线程。shutdownNow的原理是遍历线程池中的工作线程,然后逐个调用线程的interrupt方法来中断线程,所以无法响应中断的任务可能永远无法终止。shutdownNow会首先将线程池的状态设置成STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表。
只要调用了这两个关闭方法的其中一个,isShutdown方法就会返回true。当所有的任务都已关闭后,才表示线程池关闭成功,这时调用isTerminaed方法会返回true。至于我们应该调用哪一种方法来关闭线程池,应该由提交到线程池的任务特性决定,通常调用shutdown来关闭线程池,如果任务不一定要执行完,则可以调用shutdownNow。
线程执行过程
1、如果当前的线程数<corePoolSize,提交的Runnable任务,会直接作为new Thread的参数,立即执行,当提交的任务数超过了corePoolSize,就进入第二部操作2、将当前的任务提交到BlockingQueue阻塞队列中,如果Block Queue是个有界队列,当队列满了之后就进入第三步3、如果poolSize < maximumPoolsize时,会尝试new 一个Thread的进行救急处理,执行对应的runnable任务4、如果第三步也无法处理,就会用RejectedExecutionHandler来做拒绝处理
参考
- http://www.tuicool.com/articles/nUjmyq
- https://www.ibm.com/developerworks/cn/java/l-threadPool/
- https://www.ibm.com/developerworks/cn/java/j-jtp0730/
- 初识 Java 线程池
- 初识 Java 线程池
- java线程池初识
- 初识java线程池
- 初识java线程池
- 初识Java线程池
- 初识java线程
- 初识java线程
- Java线程(初识)
- Java 线程的初识
- java线程浅析[初识线程]
- java线程池(1)初识线程池
- Java多线程编程--初识线程
- java--线程初识(1)
- ThreadPoolExcutor(线程池)初识
- ThreadPoolExcutor(线程池)初识
- Java多线程编程--(1)初识线程
- 初识Java--线程同步(2)
- Qt学习之2D绘图(画刷和画笔)
- Javascript中的装饰者模式以及AOP简介
- 10.JDBC存取大对象BLOB类型
- PHP运算符陷阱
- ThinkPHP单字母函数详解
- java线程池初识
- C#遍历某目录及其子目录下所有文件的一个例子
- Statement以及PrparedStatement
- 自定义View(View的绘制与测量)
- LeetCode155. Min Stack
- 使用AJAX技术实现“动态页面静态化”
- 解决项目中无缘无故多出xxxxx.out.xml问题
- Android 上百实例源码分析以及开源分析
- Android - Shader图像渲染