Worker工作线程ThreadPoolExecutor中的工作线程并不是裸的Thread,而是被封装在了一个Worker的内部类中 。Worker实现了Runnable所以可以作为一个普通的线程来启动,在run方法中只是简单的调用了一下runWorker(runWorker后面再展开) 。Worker类有三个成员属性:
- Thread thread(被封装的工作线程对象)
- Runnable firstTask(提交任务时,创建新Worker对象时指定的第一次要执行的任务(后续线程就会去拉取工作队列里的任务执行了))
- volatile long completedTasks(统计用,计算当前工作线程总共完成了多少个任务)
【自己动手实现线程池 jdk线程池ThreadPoolExecutor工作原理解析(一)】除此之外,Worker对象还继承了AbstractQueuedSynchronizer(AQS)类,简单的实现了一个不可重入的互斥锁 。对AQS互斥模式不太了解的读者可以参考一下我之前关于AQS互斥模式的博客:AQS互斥模式与ReentrantLock可重入锁原理解析AQS中维护了一个volatile修饰的int类型的成员变量state,其具体的含义可以由使用者自己定义 。在Worker中,state的值有三种状态:
- state=-1,标识工作线程还未启动(不会被interruptIfStarted打断)
- state=0,标识工作线程已经启动,但没有开始处理任务(可能是在等待任务,idle状态)
- state=1,标识worker线程正在执行任务(runWorker方法中,成功获得任务后,通过lock方法将state设置为1)
/*** jdk的实现中令Worker继承AbstractQueuedSynchronizer并实现了一个不可重入的锁* AQS中的state属性含义* -1:标识工作线程还未启动*0:标识工作线程已经启动,但没有开始处理任务(可能是在等待任务,idle状态)*1:标识worker线程正在执行任务(runWorker中,成功获得任务后,通过lock方法将state设置为1)* */private final class MyWorker extends AbstractQueuedSynchronizer implements Runnable{final Thread thread;Runnable firstTask;volatile long completedTasks;public MyWorker(Runnable firstTask) {this.firstTask = firstTask;// newThread可能是nullthis.thread = getThreadFactory().newThread(this);}@Overridepublic void run() {runWorker(this);}protected boolean isHeldExclusively() {return getState() != 0;}protected boolean tryAcquire(int unused) {if (compareAndSetState(0, 1)) {setExclusiveOwnerThread(Thread.currentThread());return true;}return false;}protected boolean tryRelease(int unused) {setExclusiveOwnerThread(null);setState(0);return true;}public void lock(){acquire(1);}public boolean tryLock(){return tryAcquire(1);}public void unlock(){release(1);}public boolean isLocked(){return isHeldExclusively();}void interruptIfStarted() {Thread t;// 三个条件同时满足,才去中断Worker对应的thread// getState() >= 0,用于过滤还未执行runWorker的,刚入队初始化的Worker// thread != null,用于过滤掉构造方法中ThreadFactory.newThread返回null的Worker// !t.isInterrupted(),用于过滤掉那些已经被其它方式中断的Worker线程(比如用户自己去触发中断,提前终止线程池中的任务)if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {try {t.interrupt();} catch (SecurityException ignore) {}}}}execute执行提交的任务下面介绍本篇博客的重点,即线程池是如何执行用户所提交的任务的 。用户提交任务的入口是public的execute方法,Runnable类型的参数command就是提交的要执行的任务 。
经验总结扩展阅读
- 如何保护环境
- 哥哥给弟弟的生日祝福句子
- 送给自己的生日快乐句子
- 闺蜜生日快乐的祝福语
- 哪些星座善于伪装自己 不会轻易透露隐私
- 廉租房能自己装修吗 廉租房申请下来可以不住吗
- 申请廉租房需要查自己的个人征信吗 公租房与廉租房的区别在哪里
- 廉租房需要摇号吗 廉租房需要自己装修吗
- 自己手剥核桃仁怎么储存
- 我的Vue之旅 10 Gin重写后端、实现页面详情页 Mysql + Golang + Gin
