您的位置:首页 > 编程语言 > Java开发

Java线程池知识必备

2016-07-14 20:36 429 查看

线程池

简介

线程池的创建

new  ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit milliseconds,
BlockingQueue<Runnable> runnableTaskQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler);


corePoolSize(线程池基本大小)

这是一个判断该线程池是否要新建一个新的线程的标准值,如果当前线程池中的线程数小于corePoolSize,

则在接到新的请求任务时新建一个线程来处理,反之则把任务放到

BlockingQueue中,由线程池中空的线程从BlockingQueue中取出并处理;

maximumPoolSize(线程池最大大小)

线程池最大的线程数,当大于该值的时候则让RejectedExecutionHandler拒绝处理;

keepAliveTime

当线程池中大于corePoolSize的时候,部分多余的空线程会等待keepAliveTime时间,如果没有请求处理超过该时间则自行销毁;

BlockingQueue(任务队列)

保存等待任务执行的阻塞队列,有以下几种:

ArrayBlockingQueue:数组队列,先进先出;

LinkedBlockingQueue:链表队列,先进先出,吞吐量大于ArrayBlockingQueue;

SynchronousQueue:一个不存储元素的队列,每插入一个任务必须等到另一个线程调用移除操作,否则处于阻塞状态;吞吐量高于LinkedBlockingQueue,newCachedThreadPool使用的就是这个队列;

PriorityBlockingQueue:一个优先级无限阻塞的队列;

RejectedExecutionHandler(饱和策略)

当线程池处于饱和状态下,对于提交的新任务必须要有一种策略来处理;

提交任务

execute(new Runnable(){} )

没有返回值

threadsPool.execute(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
}
});


commit(new callable(){}) 返回future对象

Future future = mThreadPoolExecutor.submit(new Callable() {
@Override
public Object call() throws Exception {
return null;
}
});
--------------------------------------------------

try {
Object o = future.get();//阻塞 直到结果准备就绪
} catch (InterruptedException e) {
//中断异常
e.printStackTrace();
} catch (ExecutionException e) {
//无法执行异常
e.printStackTrace();
} finally {
//关闭线程池
mThreadPoolExecutor.shutdown();
}
}


关闭任务

原理

遍历所有的线程,逐个调用线程的interrupt方法来中断线程;

shutdown

执行shutdown后,遍历线程池中所有的线程,将状态修改为SHUTDOWN状态,然后中断正在执行任务的线程;

shutdownNow

执行shutdownNow后,遍历线程池中所有的线程,将所有线程的状态修改为STOP状态,然后尝试停止所有的线程任务

工作原理

工作流程示意图



源码分析

工作线程

合理配置线程池

任务特性

任务的性质:CPU密集型任务,IO密集型的任务,混合型任务;

任务的优先级:高,中,低;

任务的执行时间:长、中、短;

任务的依赖性,是否依赖其他系统资源,比如数据库连接。

配置意见

CPU密集型建议使用线程数尽可能少的线程池,IO密集型任务由于线程并不是一直在工作,所以建议使用线程数较多的线程池;

优先级不同任务可以使用PriorityBlockingProcessors任务队列来处理,让优先级更高的来处理(!注意:如果一直是优先级搞的任务在处理,则优先级低的任务可能无法得到处理;

时间不同的任务可以交给不同规模的线程池来处理,也可以交给优先级队列,让时间短的任务先执行;

依赖数据库连接池的任务,由于提交SQL后需要等待返回结果,所以等待的时间越长,CPU空闲的时间越长,为了提高CPU的利用率,可以通过增大线程池的线程数。

建议使用有界队列,这样更加稳定安全,防止撑爆内存(如果线程一直处于阻塞状态,新的任务来的时候就会新建新的线程,直到内存不足)。

线程池的监控

部分线程池的属性参数

taskCount:线程池需要执行的任务数量;

completedTaskCont: 已经完成的任务数量;

largestPoolSize: 线程池曾经创建过的最大线程数,可以看看是否大于最大线程数,是否满过;

getPoolSize: 线程池的线程数量,线程池不销毁,池中的线程不会自动销毁

getAliveCount:活动状态的线程数。

通过扩展线程池进行监控

继承线程池;

重写beforeExecute,afterExecute和terminated方法。

常用线程池

FixedThreadPool 定长并发线程池

源码

public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}


特点:

可以创建固定的线程数,当线程数达到corePoolSize的时候,再添加任务就放到LinkedBlockingQueue这个无界的队列里边,等待空闲的线程来取任务执行任务,空闲线程不会被回收;

SingleThreadExecutor 顺序执行线程池

源码

public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}


特点

corePoolSize为1,既最多只能有一个线程工作,当其他任务来的时候都放到LinkedBlockingQueue任务队列里边,等待线程工作完后,再从队列里边取,逐个执行,相当于顺序执行;

CachedThreadPool “无限”容量可缓存线程池

源码

public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}


特点

SynchronousQueue是一个没有容量的阻塞队列,每个插入必须有对应的移除操作;

如果没有线程去从SynchronousQueue从事移除的工作,那么就会新建一个线程来执行任务,如果一直这么下去,就可以能因为创建过多的线程耗尽CPU资源;

如果空闲的线程等待时间超过60秒,而且没有新的任务,会自动被回收。

ScheduledThreadPool 定时线程池

参考资料:

JAVA编程思想

JDK1.6源码

聊聊并发——方腾飞

Java中常见的线程池
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: