在手写一个线程池前,我们先参考一下JDK里的线程池是怎么工作的。
一、JDK线程池的七大参数
1.corePoolSize:线程池中常驻核心线程数
2.maximumPoolSize:线程池能够容纳同时执行的最大线程数,必须大于等于1
3.keepAliveTime:多余的空闲线程的存活时间,当前线程池数量超过corePoolSize时,
4.unit:keepAliveTime的单位
5.workQueue:任务队列,被提交但尚未被执行的任务
6.threadFactory:表示生成线程池中工作线程的线程工厂,用于创建线程一般用默认的即可
这个简单理解成是xxx银行的标志,默认不用管。
7.handler:拒绝策略,表示当队列满了并且工作线程大于等于线程池的最大线程数(maximumPoolSize)时如何来拒绝请求执行的runable的策略
二、线程池的工作流程
明白了JDK线程池的基本元素与工作流程之后,我们模仿它写一个简单的线程池
三、写一个线程池类
首先定义一个线程池接口
public interface ThreadPool {
/**
* 执行具体的task
*/
void excute(Runnable task);
/**
* 处理提交的任务
*
* @param task
*/
void submit(Runnable task);
}
然后实现它。
这里我们不按照JDK线程池的工作原理,而是先实现一个简单的线程池:初始化一批常驻线程,然后每新来一个任务,就把它放到阻塞队列中,让这些线程自己去队列中取任务消费。
public class MThreadPool implements ThreadPool {
//线程数量
private int workNum;
//任务数量
private int taskNum;
//任务【阻塞】队列,被提交但尚未被执行的任务
private BlockingQueue<Runnable> taskQueue;
//表示生成线程池中工作线程的线程工厂
private ThreadFactory threadFactory;
//存放工作线程的容器
private final Set<WorkerThread> workers = new HashSet();
//初始化线程池
public MThreadPool(int workNum, BlockingQueue blockingQueue, ThreadFactory threadFactory){
this.workNum = workNum;
this.taskQueue = blockingQueue;
this.threadFactory = threadFactory;
initWorker();
}
public void initWorker(){
//启动一定数量的线程数,从队列中获取任务处理
for (int i=0;i<workNum;i++) {
WorkerThread workThread = new WorkerThread("thead_"+i, threadFactory);
workThread.start();
workers.add(workThread);
}
}
//工作线程类
private class WorkerThread extends Thread{
public WorkerThread(String name, ThreadFactory factory){
setName(name);
factory.newThread(this);
}
@Override
public void run() {
Runnable runnable = null;
try {
while (! isInterrupted()) { //如果没有被标记中断,则从对阻塞队列中取出任务执行
runnable = taskQueue.get(); //take:阻塞接口的移除方法
if (runnable != null) {
System.out.println("Thread ID:" + getName() + " ready exec:" + runnable.toString());
runnable.run();
}
runnable = null; //help gc
}
} catch (Exception e) {
// TODO: handle exception
}
}
//线程停止工作
public void stopWork() {
interrupt();
}
}
@Override
public void excute(Runnable task) {
try {
taskQueue.put(task); //put:阻塞接口的插入
} catch (Exception e) {
// TODO: handle exception
}
}
@Override
public void destory() {
for(WorkerThread workerThread:workers){
workerThread.stopWork();
}
}
}
在这个实现中,线程池在初始化的时候就创建了工作线程,工作线程直接消费队列中的任务。这个实现中,线程池并不会根据任务数量灵活的创建、销毁线程。如果队列中没有任务,线程将空等,消耗性能。现在,我们以上面的实现作为基础,将JDK线程池的设计思想加进来。
public class MXThreadPool extends Thread implements ThreadPool {
//任务【阻塞】队列,被提交但尚未被执行的任务
private BlockingQueue<Runnable> taskQueue;
//表示生成线程池中工作线程的线程工厂
private ThreadFactory threadFactory;
//最大线程数
private int maxSize;
//核心线程数
private int coreSize;
//线程存活时间
private long keepAliveTime;
//当前活跃线程的数量
private int activeCount;
//存放工作线程的容器
private final Set<WorkerThread> workers = new HashSet();
//初始化线程池
public MXThreadPool(int maxSize, int coreSize, BlockingQueue blockingQueue,
ThreadFactory threadFactory, long keepAliveTime){
this.maxSize = maxSize;
this.coreSize = coreSize;
this.taskQueue = blockingQueue;
this.threadFactory = threadFactory;
this.keepAliveTime = keepAliveTime;
this.activeCount = 0;
}
//创建新的任务线程并启动
private void newThread() {
WorkerThread workThread = new WorkerThread("thead_"+this.activeCount++, threadFactory);
workThread.start();
workers.add(workThread);
}
//移除一个工作线程
private void removeThread() {
Iterator<WorkerThread> iterator = workers.iterator();
if(iterator.hasNext()){
WorkerThread workerThread = iterator.next();
workerThread.stopWork();
this.activeCount--;
}
}
@Override
public void run() {
//自动维护线程池
while (!isInterrupted()) {
try {
Thread.sleep(keepAliveTime);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
synchronized (this) {
//当任务队列大于0,活跃线程小于核心线程的时候,扩容线程
if (taskQueue.size() > 0 && activeCount < coreSize) {
for (int i = 0; i < coreSize-activeCount; i++) {
newThread();
}
continue;
}
//当任务队列大于0,活跃线程小于最大线程的时候,扩容线程
if (taskQueue.size() > 0 && activeCount < maxSize) {
for (int i = 0; i < maxSize-activeCount; i++) {
newThread();
}
}
//当任务队列等于0,活跃线程大于核心线程的时候,缩减线程
if (taskQueue.size() == 0 && activeCount > coreSize) {
for (int i = 0; i < activeCount-coreSize; i++) {
removeThread();
}
}
}
}
}
//工作线程类
private class WorkerThread extends Thread{
public WorkerThread(String name, ThreadFactory factory){
setName(name);
factory.newThread(this);
}
@Override
public void run() {
Runnable runnable = null;
try {
while (! isInterrupted()) { //如果没有被标记中断,则从对阻塞队列中取出任务执行
runnable = taskQueue.get(); //take:阻塞接口的移除方法
if (runnable != null) {
System.out.println("Thread ID:" + getName() + " ready exec:" + runnable.toString());
runnable.run();
}
runnable = null; //help gc
}
} catch (Exception e) {
// TODO: handle exception
}
}
//线程停止工作
public void stopWork() {
interrupt();
}
}
@Override
public void excute(Runnable task) {
try {
taskQueue.put(task); //put:阻塞接口的插入
} catch (Exception e) {
// TODO: handle exception
}
}
@Override
public void destory() {
for(WorkerThread workerThread:workers){
workerThread.stopWork();
}
}
}