实现一个固定数量线程池,主要用到消息队列实现任务仓库以及特定数量的工作线程。完整代码贴在后面,给出了测试方法,值得注意点在于对线程池进行中断的时候的一系列连锁反应,以及使用Collections.synchronizedList同步普通数组使之变为线程安全的技巧。详见代码注释。
//实现固定数量线程池 主要用到消息队列实现任务仓库 以及特定数量的工作线程
//最值得注意的是 中断的时候 以及使用Collections.synchronizedList 方法同步普通数组的时候
public class FixedSizeThreadPool {
//增加一个变量判断线程池的状态 是不是正在工作
private volatile boolean isWorking =true;
//需要仓库 使用阻塞队列
private BlockingQueue<Runnable> blockQueue;
//线程的集合
private List<Thread> wokers;
//工作线程
static class Worker extends Thread{
private FixedSizeThreadPool pool;
public Worker(FixedSizeThreadPool pool){
this.pool =pool;
}
@Override
public void run(){
while (this.pool.isWorking||this.pool.blockQueue.size()>0){
Runnable task =null;
try {
if(this.pool.isWorking)
task=this.pool.blockQueue.take();
else
task = this.pool.blockQueue.poll();
if(task!=null){
//非常值得注意的是,Runnable接口中是不存在start方法的,唯一的就是run方法 调用run方法相当于使用普通方法
task.run();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//把任务提交到任务仓库的方法
public boolean submit(Runnable task){
if(isWorking)
return this.blockQueue.offer(task);
else
return false;
}
//线程池的初始化
public FixedSizeThreadPool(int poolSize,int taskSize){
if(poolSize<=0 || taskSize<=0) throw new IllegalArgumentException("非法参数");
this.blockQueue = new LinkedBlockingDeque<>(taskSize);
this.wokers = Collections.synchronizedList( new ArrayList<>());
for(int i =0; i < poolSize ; i++){
Worker worker = new Worker(this);
worker.start();
wokers.add(worker);
}
}
//关闭线程池的方法
//需要注意的是四个方面
//1.仓库停止接受任务
//2.仓库中的剩余的任务继续的执行
//3.拿任务的时候 不要阻塞了
//4.一旦任务阻塞了,中断线程
public void shutdown(){
this.isWorking =false;
for(Thread thread: wokers){
if(thread.getState().equals(Thread.State.BLOCKED)){
//中断掉
thread.interrupt();
}
}
}
public static void main(String[] args){
FixedSizeThreadPool fixedSizeThreadPool = new FixedSizeThreadPool(3, 6);
for(int i =0; i < 6 ; i++){
fixedSizeThreadPool.submit(new Runnable() {
@Override
public void run() {
System.out.println("放入一个新的线程");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
System.out.println("线程池满了");
}
}
});
}
fixedSizeThreadPool.shutdown();
}
}