1.手写之前首先展示一张原理图:
这里面有几个核心点:
⑴线程池里的核心线程数与最大线程数
⑵线程池里真正工作的线程worker
⑶线程池里用来存取任务的队列BlockingQueue
顺便补充点阻塞队列的知识:
add 增加一个元索 如果队列已满,则抛出一个IIIegaISlabEepeplian异常
remove 移除并返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常
element 返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常
offer 添加一个元素并返回true 如果队列已满,则返回false
poll 移除并返问队列头部的元素 如果队列为空,则返回null
peek 返回队列头部的元素 如果队列为空,则返回null
put 添加一个元素 如果队列满,则阻塞
take 移除并返回队列头部的元素 如果队列为空,则阻塞
⑷线程中的任务task
2.实现
本例实现简化了一些,只实现了BlockingQueue存放任务,然后每个worker取任务并执行,这当然是最简单实现,JDK的实现比这强大的多,而且还具备当工作线程处理不过来时,可以产生新的线程来处理任务,这个数量不能超过原先定义的最大线程数,而在本例中都没实现这些功能。另外没有对任务队列和线程池加锁,这样是线程不安全的,
package doThreadPool;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import antlr.collections.List;
public class ThreadExcutor {
private volatile boolean RUNNING=true;
//阻塞队列
private static BlockingQueue<Runnable> queue=null;
//对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。
private final HashSet<Worker> workers = new HashSet<Worker>();
private final ArrayList<Thread> threadList = new ArrayList<Thread>();
int poolSize = 0;
int coreSize = 0;
boolean shutdown = false;
//构造函数,
public ThreadExcutor(int poolSize){
this.poolSize = poolSize;
queue = new LinkedBlockingQueue<Runnable>(poolSize);
}
public void exec(Runnable runnable) {
if (runnable == null) throw new NullPointerException();
if(coreSize < poolSize){
addThread(runnable);
}else{
//System.out.println("offer" + runnable.toString() + " " + queue.size());
try {
queue.put(runnable); //coreSize>poolSzie 加入阻塞队列中去
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void addThread(Runnable runnable){
coreSize ++; //正在工作的线程+1
Worker worker = new Worker(runnable); //
workers.add(worker);
Thread t = new Thread(worker);
threadList.add(t);
try {
t.start();
}catch (Exception e){
e.printStackTrace();
}
}
public void shutdown() {
RUNNING = false;
if(!workers.isEmpty()){
for (Worker worker : workers){
worker.interruptIfIdle();
}
}
shutdown = true;
Thread.currentThread().interrupt();
}
class Worker implements Runnable{
public Worker(Runnable runnable){
queue.offer(runnable); //将这个runable将入到队列中去
}
@Override
public void run() {
while (true && RUNNING){
if(shutdown == true){
Thread.interrupted();
}
Runnable task = null;
try {
task = getTask();
task.run();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public Runnable getTask() throws InterruptedException {
return queue.take();
}
public void interruptIfIdle() {
for (Thread thread :threadList) {
System.out.println(thread.getName() + " interrupt");
thread.interrupt();
}
}
}}
package doThreadPool;
public class TheadBlockedQ {
public static void main(String[] args) throws InterruptedException {
ThreadExcutor excutor = new ThreadExcutor(3);
for (int i = 0; i < 10; i++) {
excutor.exec(new Runnable() {
@Override
public void run() {
System.out.println("线程 " + Thread.currentThread().getName() + " 在帮我干活");
}
});
}
excutor.shutdown();
}
}
输出:
线程 Thread-0 在帮我干活
线程 Thread-1 在帮我干活
线程 Thread-1 在帮我干活
线程 Thread-2 在帮我干活
线程 Thread-0 在帮我干活
线程 Thread-1 在帮我干活
线程 Thread-1 在帮我干活
线程 Thread-1 在帮我干活
线程 Thread-2 在帮我干活
线程 Thread-0 在帮我干活
Thread-0 interrupt
Thread-1 interrupt
Thread-2 interrupt
Thread-0 interrupt
Thread-1 interrupt
Thread-2 interrupt
Thread-0 interrupt
Thread-1 interrupt
Thread-2 interrupt