java线程池之ThreadPoolExecutor
Posted 红桃xin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java线程池之ThreadPoolExecutor相关的知识,希望对你有一定的参考价值。
java线程池之ThreadPoolExecutor
why
为什么你需要线程池?答案往往是当你开发个简单并发的java程序,或者创建Runnable对象,用Thread来执行。创建一个java线程是个非常昂贵的操作。如果每次创建新的线程实例执行Task, 应用表现是糟糕的。
如何创建线程池
一个线程池是一组预先定义的线程集合。一般来说,池的大小是固定的,但是不是强制的。这方便用相同的线程执行多个任务。如果有任务大于池的大小,需要在队列里等待FIFO
ThreadPoolExecutor
自从java5, java并发api提供Executor framework机制。实现Executor和ExecutorService。
它分隔任务创建和执行。你必须实现Runnable接口,然后用executor执行。当你发送任务到executor,它会努力使用线程池执行此任务,去避免连续新增线程。
怎么使用
- 固定线程池 - 创建线程池复用固定数量的线程执行任何数量的任务。当所有线程在执行状态,再提交额外的任务,他们等待在队列中直到线程空闲。大部分的最佳实现
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);
2.缓存线程池 - 创建线程池尽可能需要的。但是也会复用先前构建的空闲线程。如果有耗时任务,不要使用
此线程池。当线程数超过系统可以处理的数目,这会拖垮整个系统。
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newCachedThreadPool();
3.计划线程池- 设定给定的延迟或者执行周期的计划命令
ThreadPoolExecutor executor = (ThreadPoolExecutor)Executors.newScheduledThreadPool(10);
- 单线程池 - 创建单线程执行所有任务。当只有一个任务时使用。
ThreadPoolExecutor executor = (ThreadPoolExecutor)Executors.newSingleThreadExecutor();
- 任务窃取线程池 - 创建一个线程池维护足够线程去支持足够量的并发量。换句话,在多处理器机器的同时时间点用最大数量的线程执行给定的任务。
ThreadPoolExecutor executor = (ThreadPoolExecutor)Executors.newWorkStealingPool(4);
ThreadPoolExecutor 例子
- 创建task - 创建一个任务 [每次使用随机时间完成]
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
public class ThreadPoolExample
{
public static void main(String[] args)
{
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);
for (int i = 1; i <= 5; i++)
{
Task task = new Task("Task " + i);
System.out.println("Created : " + task.getName());
executor.execute(task);
}
executor.shutdown();
}
}
- 使用线程池执行任务
创建5个任务和创建执行队列。这个执行器有二个线程去执行所有任务。
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
public class ThreadPoolExample
{
public static void main(String[] args)
{
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);
for (int i = 1; i <= 5; i++)
{
Task task = new Task("Task " + i);
System.out.println("Created : " + task.getName());
executor.execute(task);
}
executor.shutdown();
}
}
Program output:
Created : Task 1
Created : Task 2
Created : Task 3
Created : Task 4
Created : Task 5
Executing : Task 1
Executing : Task 2
Executing : Task 3
Executing : Task 4
Executing : Task 5
总结
- ThreadPoolExecutor 类有四个不同构造方法,但是由于他们复杂性,java目前的api提供 Executors使用线程池。相对直接创建线程池,比较推荐使用Executors类。
- 缓存池
the chached thread pool好处是方便,坏处是如果超过系统处理能力,使系统载。可以用固定线程池解决,下个博客再说吧。 - 关键层面,你必须显式结束。要不然,executor会继续执行,程序不会结束。
- 可以使用**ThreadPoolExecutor.shutdown()关闭,当完成所有在执行任务。调用shutdown()**后,你再发送其它任务,它会拒绝,然后throw 异常RejectedExecutionException
- 提供很多方法获取线程池相关的信息和状态。例如:getPoolSize() , getActiveCount(), getCompletedTaskCount() , getLargestPoolSize()
- 结束执行器有下面方法:
- shutdownNow(): 立即关闭executor. 返回pending任务list。正在running的任务不会因为这个方法调用结束,而是继续执行。
- isTerminated():如果执行 shutdown() 或者 shutdownNow() 方法并且完成关闭,就会返回true
- isShutdown(): 如果 执行shutdown() 返回true
- awaitTermination(long timeout, TimeUnit unit): 此方法blocks the calling thread , 等到执行器结束或者超时发生. TimeUnit是枚举类
DAYS,HOURS,MICROSECONDS ETC
以上是关于java线程池之ThreadPoolExecutor的主要内容,如果未能解决你的问题,请参考以下文章