今天看了线程池的源码,实现了一下线程池的思想。(第一次写的时候还死锁了···)
其实线程池最大的问题在于,如何让线程一直活着。毕竟线程执行完run方法就会变成终止态。如果不能一直活着,也就无法池化了。
解决线程一直活着的方法就是让线程在run方法中不断访问父作用域的阻塞队列获取任务。阻塞队列中的阻塞方法帮助线程阻塞,延长它的寿命。
public class MyThreadPool {
class Worker implements Runnable{
private Runnable task;
private Thread thread;
public Worker() {
this.task = null;
//这里一开始死锁了
}
@Override
public void run() {
work(this);
}
}
private void work(Worker worker) {
while (true) {
try {
if (worker.task == null) {
worker.task = works.take();
worker.task.run();
worker.task = null;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private final BlockingQueue<Runnable> works;
private final HashSet<Worker> workers;
public MyThreadPool(){
works = new ArrayBlockingQueue<>(10);
workers = new HashSet<>();
for (int i=0; i<5; i++) {
Worker worker = new Worker();
Thread t = new Thread(worker);
worker.thread = t;
t.start();
}
}
public void execute(Runnable runnable) {
works.offer(runnable);
}
// public static MyThreadPool getSingleton() {
// return singleton;
// }
// private static final MyThreadPool singleton = new MyThreadPool();
public static void main(String[] args) {
MyThreadPool pool = new MyThreadPool();
try {
while (true) {
pool.execute(() -> {
try {
System.out.println(Thread.currentThread().getName() + "在干活,花费一秒");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread.sleep(500);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
最开始没处理好worker类的构造函数,在里面直接初始化thread导致了循环引用问题。
解决方法就是在后面用set方法(这里是包作用域所以不用写setter,但是本质是setter)单独赋值,把环破开即可。