这么说吧,java线程池的实现原理其实很简单 (3)

这么说吧,java线程池的实现原理其实很简单

线程池的工作线程通过Woker类实现,在ReentrantLock锁的保证下,把Woker实例插入到HashSet后,并启动Woker中的线程,其中Worker类设计如下:

1、继承了AQS类,可以方便的实现工作线程的中止操作;

2、实现了Runnable接口,可以将自身作为一个任务在工作线程中执行;

3、当前提交的任务firstTask作为参数传入Worker的构造方法;

这么说吧,java线程池的实现原理其实很简单

从Woker类的构造方法实现可以发现:线程工厂在创建线程thread时,将Woker实例本身this作为参数传入,当执行start方法启动线程thread时,本质是执行了Worker的runWorker方法。

runWorker实现

这么说吧,java线程池的实现原理其实很简单

runWorker方法是线程池的核心:

1、线程启动之后,通过unlock方法释放锁,设置AQS的state为0,表示运行中断;

2、获取第一个任务firstTask,执行任务的run方法,不过在执行任务之前,会进行加锁操作,任务执行完会释放锁;

3、在执行任务的前后,可以根据业务场景自定义beforeExecute和afterExecute方法;

4、firstTask执行完成之后,通过getTask方法从阻塞队列中获取等待的任务,如果队列中没有任务,getTask方法会被阻塞并挂起,不会占用cpu资源;

getTask实现

这么说吧,java线程池的实现原理其实很简单

整个getTask操作在自旋下完成:

1、workQueue.take:如果阻塞队列为空,当前线程会被挂起等待;当队列中有任务加入时,线程被唤醒,take方法返回任务,并执行;

2、workQueue.poll:如果在keepAliveTime时间内,阻塞队列还是没有任务,则返回null;

所以,线程池中实现的线程可以一直执行由用户提交的任务。

Future和Callable实现

通过ExecutorService.submit()方法提交的任务,可以获取任务执行完的返回值。

这么说吧,java线程池的实现原理其实很简单

在实际业务场景中,Future和Callable基本是成对出现的,Callable负责产生结果,Future负责获取结果。

1、Callable接口类似于Runnable,只是Runnable没有返回值。

2、Callable任务除了返回正常结果之外,如果发生异常,该异常也会被返回,即Future可以拿到异步执行任务各种结果;

3、Future.get方法会导致主线程阻塞,直到Callable任务执行完成;

submit实现

这么说吧,java线程池的实现原理其实很简单

通过submit方法提交的Callable任务会被封装成了一个FutureTask对象。

FutureTask

这么说吧,java线程池的实现原理其实很简单

1、FutureTask在不同阶段拥有不同的状态state,初始化为NEW;

2、FutureTask类实现了Runnable接口,这样就可以通过Executor.execute方法提交FutureTask到线程池中等待被执行,最终执行的是FutureTask的run方法;

FutureTask.get实现

这么说吧,java线程池的实现原理其实很简单

内部通过awaitDone方法对主线程进行阻塞,具体实现如下:

这么说吧,java线程池的实现原理其实很简单

1、如果主线程被中断,则抛出中断异常;

2、判断FutureTask当前的state,如果大于COMPLETING,说明任务已经执行完成,则直接返回;

3、如果当前state等于COMPLETING,说明任务已经执行完,这时主线程只需通过yield方法让出cpu资源,等待state变成NORMAL;

4、通过WaitNode类封装当前线程,并通过UNSAFE添加到waiters链表;

5、最终通过LockSupport的park或parkNanos挂起线程;

FutureTask.run实现

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zgdjsy.html