java的线程池有几种 java线程的创建方式( 四 )


阻塞队列(BlockingQueue)是一个支持两个附加操作的队列 。这两个附加的操作是:在队列为空时 , 获取元素的线程会等待队列变为非空 。当队列满时 , 存储元素的线程会等待队列可用 。阻塞队列常用于生产者和消费者的场景 , 生产者是往队列里添加元素的线程 , 消费者是从队列里拿元素的线程 。阻塞队列就是生产者存放元素的容器 , 而消费者也只从容器里拿元素 。
下图中展示了线程1往阻塞队列中添加元素 , 而线程2从阻塞队列中移除元素:

java的线程池有几种 java线程的创建方式

文章插图
图5 阻塞队列
使用不同的队列可以实现不一样的任务存取策略 。在这里 , 我们可以再介绍下阻塞队列的成员:

java的线程池有几种 java线程的创建方式

文章插图
2.3.3 任务申请
由上文的任务分配部分可知 , 任务的执行有两种可能:一种是任务直接由新创建的线程执行 。另一种是线程从任务队列中获取任务然后执行 , 执行完任务的空闲线程会再次去从队列中申请任务再去执行 。第一种情况仅出现在线程初始创建的时候 , 第二种是线程获取任务绝大多数的情况 。
线程需要从任务缓存模块中不断地取任务执行 , 帮助线程从阻塞队列中获取任务 , 实现线程管理模块和任务管理模块之间的通信 。这部分策略由getTask方法实现 , 其执行流程如下图所示:

java的线程池有几种 java线程的创建方式

文章插图
图6 获取任务流程图
getTask这部分进行了多次判断 , 为的是控制线程的数量 , 使其符合线程池的状态 。如果线程池现在不应该持有那么多线程 , 则会返回null值 。工作线程Worker会不断接收新任务去执行 , 而当工作线程Worker接收不到任务的时候 , 就会开始被回收 。
2.3.4 任务拒绝
任务拒绝模块是线程池的保护部分 , 线程池有一个最大的容量 , 当线程池的任务缓存队列已满 , 并且线程池中的线程数目达到maximumPoolSize时 , 就需要拒绝掉该任务 , 采取任务拒绝策略 , 保护线程池 。
拒绝策略是一个接口 , 其设计如下:
publicinterfaceRejectedExecutionHandler{voidrejectedExecution(Runnabler,ThreadPoolExecutorexecutor);}用户可以通过实现这个接口去定制拒绝策略 , 也可以选择JDK提供的四种已有拒绝策略 , 其特点如下:

java的线程池有几种 java线程的创建方式

文章插图
2.4 Worker线程管理
2.4.1 Worker线程
线程池为了掌握线程的状态并维护线程的生命周期 , 设计了线程池内的工作线程Worker 。我们来看一下它的部分代码:
privatefinalclassWorkerextendsAbstractQueuedSynchronizerimplementsRunnable{finalThreadthread;//Worker持有的线程RunnablefirstTask;//初始化的任务 , 可以为null}Worker这个工作线程 , 实现了Runnable接口 , 并持有一个线程thread , 一个初始化的任务firstTask 。thread是在调用构造方法时通过ThreadFactory来创建的线程 , 可以用来执行任务;firstTask用它来保存传入的第一个任务 , 这个任务可以有也可以为null 。如果这个值是非空的 , 那么线程就会在启动初期立即执行这个任务 , 也就对应核心线程创建时的情况;如果这个值是null , 那么就需要创建一个线程去执行任务列表(workQueue)中的任务 , 也就是非核心线程的创建 。

推荐阅读