1.java常用的线程池
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();//缓存线程池
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);//固定大小线程池
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();//单线程的线程池
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);任务线程池
2.常用线程池都指向了同一个类ThreadPoolExecutor
看看上述常用线程池的源码:
缓存线程池生成源码:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
固定大小线程池生成源码:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
单线程的线程池生成源码:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
任务线程池生成源码:
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
new DelayedWorkQueue());
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
从上述我们发现:其实这些常用的线程池最终使用的都是ThreadPoolExecutor这个线程池的类,那么我们重点了解下ThreadPoolExecutor这个类
3.ThreadPoolExecutor类
我们先看下这个类的构造函数:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
这四个构造函数,最终都指向了最后一个构造函数:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {}
下面分析一下里面的参数:
corePoolSize:核心池的线程数量。正常情况下,创建的线程池没有任何线程(调用prestartCoreThread()和prestartAllCoreThreads()除外,这两个方法是表示在线程池中预创建corePoolSize个线程)。正常情况下,创建了线程池后,每到达一个任务,就会创建一个线程去执行任务,当线程池中的线程数量达到corePoolSize后,就会把达到的任务放到缓存队列中。缓存队列是后面的一个参数,一会就介绍。
maximumPoolSize:线程池的最大线程数。表示最多能创建多少个线程
keepAliveTime:正常情况下,线程池中的线程数大于corePoolSize时,并且存在没有任务执行的线程,当这些线程保持keepAliveTime这个参数的时间时,线程就会被终止并释放,当然终止和释放到corePoolSize数量为止。但是非正常情况下,调用allowCoreThreadTimeOut(boolean)时,线程池中的长时间未执行的线程数量就会被终止和释放到0为止。
unit:参数keepAliveTime的取值单位。
TimeUnit.DAYS; //天
TimeUnit.HOURS; //小时
TimeUnit.MINUTES; //分钟
TimeUnit.SECONDS; //秒
TimeUnit.MILLISECONDS; //毫秒
TimeUnit.MICROSECONDS; //微妙
TimeUnit.NANOSECONDS; //纳秒
workQueue:这个就是corePoolSize参数中提到的缓存队列,一般使用LinkedBlockingQueue或SynchronousQueue。
threadFactory:线程工厂,主要用来创建线程。
handler:拒绝处理任务时的策略。
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
4.ThreadPoolExecutor类的继承关系
ThreadPoolExecutor继承了AbstractExecutorService,AbstractExecutorService实现了ExecutorService,ExecutorService继承了Executor。
其中经常用到的方法如下:
execute():向线程池提交一个任务,由线程池去执行
submit():向线程池提交一个任务,它与execute()的不同之处在于,它能返回Future的执行结果,具体应用可以看后面的例子
shutdown()和shutdownNow():关闭线程池
5.常用线程池的作用与示例:注意下面的示例有的没有调用shutdown()关掉线程池。
-
newCachedThreadPool
缓存线程池:它的线程池数量默认达到Integer.MAX_VALUE,可以放大量的线程。但是就是因为可以放大量的线程,所以要在程序中控制线程的数量,否则,线程量太大,很容易造成系统的瘫痪。
/**
* Created by
* Date : 2018/7/19 14:12
*/
public class Main {
public static void main(String[] args){
new Main().test1();
}
public void test1(){
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for(int i=1;i<=5;i++){
final int index=i;
cachedThreadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println("线程"+index+"执行");
}
});
}
}
}
执行结果:
线程1执行
线程4执行
线程5执行
线程3执行
线程2执行
-
newFixedThreadPool
固定大小线程池:固名思义,就是可以放固定的线程数量。
/**
* Created by WangZhiXin
* Date : 2018/7/19 14:12
*/
public class Main {
public static void main(String[] args) {
new Main().test2();
}
public void test2() {
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
for (int i = 6; i <= 10; i++) {
final int index = i;
fixedThreadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println("线程" + index + "执行");
try{
TimeUnit.SECONDS.sleep(2);
}catch (Exception e){
e.printStackTrace();
}
}
});
}
}
}
执行结果:
线程6执行
线程7执行
线程8执行
线程9执行
线程10执行
这个执行结果是每2秒打印三个线程的内容。也就是执行三个线程。
-
newSingleThreadExecutor
单线程线程池:只有一个线程执行任务
/**
* Created by WangZhiXin
* Date : 2018/7/19 14:12
*/
public class Main {
public static void main(String[] args) {
new Main().test3();
}
public void test3() {
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 6; i <= 10; i++) {
final int index = i;
singleThreadExecutor.execute(new Runnable() {
@Override
public void run() {
System.out.println("线程" + index + "执行");
try{
TimeUnit.SECONDS.sleep(1);
}catch (Exception e){
e.printStackTrace();
}
}
});
}
singleThreadExecutor.shutdown();
}
}
执行结果:
线程6执行
线程7执行
线程8执行
线程9执行
线程10执行
每隔一秒执行一次
-
newScheduledThreadPool
任务线程池:可以按固定时间执行线程。
比如下面的例子:
/**
* Created by WangZhiXin
* Date : 2018/7/19 14:12
*/
public class Main {
public static void main(String[] args) {
new Main().test4();
}
public void test4() {
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("线程执行");
}
}, 1, 3, TimeUnit.SECONDS);
}
}
执行结果:
线程执行
线程执行
线程执行
线程执行
线程执行
。。。。。。
结果是1秒后每隔3秒执行一次,注意这个方法不能加shutDown()方法,否则会被直接关掉
前面都是演示execute()方法的例子,下面再演示一个submit()方法,有返回Future的执行结果的例子:
/**
* Created by
* Date : 2018/7/19 14:12
*/
public class Main {
public static void main(String[] args) {
new Main().test5();
}
public void test5(){
List<Integer> list=new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
if (!list.isEmpty()) {
int size = list.size();
ExecutorService pool = Executors.newFixedThreadPool(size > 2 ? 2 : size);
final List<Exception> errorList = new ArrayList();
List<Future> rowResult = new CopyOnWriteArrayList<Future>();
for (int i = 0; i < size; i++) {
final Integer index = list.get(i);
rowResult.add(pool.submit(new Runnable() {
@Override
public void run() {
try {
System.out.println(index);
} catch (Exception e) {
//添加异常信息
errorList.add(e);
}
}
}));
}
//等待处理结果
for (Future f : rowResult) {
try{
f.get();
}catch (Exception e){
e.printStackTrace();
}
}
//启动一次顺序关闭,执行以前提交的任务,但不接受新任务。如果已经关闭,则调用没有其他作用
pool.shutdown();
if (!errorList.isEmpty()) {
//抛出异常信息
System.out.println("异常信息:"+errorList.get(0).getMessage());
}
}
}
}
执行结果:
1
2
3
5
4
其中f.get()这个方法是阻塞等待处理结果,直到所有线程都处理完了并返回Future,f.get()才不会阻塞。