今天看了线程池的源码,实现了一下线程池的思想。(第一次写的时候还死锁了···)
其实线程池最大的问题在于,如何让线程一直活着。毕竟线程执行完run方法就会变成终止态。如果不能一直活着,也就无法池化了。
解决线程一直活着的方法就是让线程在run方法中不断访问父作用域的阻塞队列获取任务。阻塞队列中的阻塞方法帮助线程阻塞,延长它的寿命。
public class MyThreadPool {class Worker implements Runnable{private Runnable task;private Thread thread;public Worker() {this.task = null;//这里一开始死锁了}@Overridepublic 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)单独赋值,把环破开即可。
