1700450579
1700450580
本次代码执行了4遍线程体,按照我们之前阐述的“一个线程不可能从结束状态转变为可运行状态”,那为什么此处的2个线程可以反复使用呢?这就是我们要搞清楚的重点。
1700450581
1700450582
线程池的实现涉及以下三个名词:
1700450583
1700450584
(1)工作线程(Worker)
1700450585
1700450586
线程池中的线程,只有两个状态:可运行状态和等待状态,在没有任务时它们处于等待状态,运行时可以循环地执行任务。
1700450587
1700450588
(2)任务接口(Task)
1700450589
1700450590
这是每个任务必须实现的接口,以供工作线程调度器调度,它主要规定了任务的入口、任务执行完的场景处理、任务的执行状态等。这里有两种类型的任务:具有返回值(或异常)的Callable接口任务和无返回值并兼容旧版本的Runnable接口任务。
1700450591
1700450592
(3)任务队列(Wok Queue)
1700450593
1700450594
也叫做工作队列,用于存放等待处理的任务,一般是BlockingQueue的实现类,用来实现任务的排队处理。
1700450595
1700450596
我们首先从线程池的创建说起,Executors.newFixedThreadPool(2)表示创建一个具有2个线程的线程池,源代码如下:
1700450597
1700450598
public class Executors{
1700450599
1700450600
public static ExecutorService newFixedThreadPool(int nThreads){
1700450601
1700450602
//生成一个最大为nThreads的线程池执行器
1700450603
1700450604
return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.
1700450605
1700450606
MILLISECONDS, new LinkedBlockingQueue<Runnable>());
1700450607
1700450608
}
1700450609
1700450610
}
1700450611
1700450612
这里使用了LinkedBlockingQueue作为任务队列管理器,所有等待处理的任务都会放在该队列中,需要注意的是,此队列是一个阻塞式的单端队列。线程池建立好了,那就需要线程在其中运行了,线程池中的线程是在submit第一次提交任务时建立的,代码如下:
1700450613
1700450614
public Future<?>submit(Runnable task){
1700450615
1700450616
//检查任务是否为null
1700450617
1700450618
if(task==null)throw new NullPointerException();
1700450619
1700450620
//把Runnable任务包装成具有返回值的任务对象,不过此时并没有执行,只是包装
1700450621
1700450622
RunnableFuture<Object>ftask=newTaskFor(task, null);
1700450623
1700450624
//执行此任务
1700450625
1700450626
execute(ftask);
1700450627
1700450628
//返回任务预期执行结果
[
上一页 ]
[ :1.700450579e+09 ]
[
下一页 ]