一、线程池的作用Thread其实是一种特别重量级的资源,创建、启动、销毁其实都是比较耗费系统资源的,因此对于线程的重复利用是一种特别好的编程习惯,加之程序中可创建的线程数量是有限的,一般系统的性能越好,可以创建的线程数目就越多。但是当线程创建的越多时,系统的性能就会越差。自JDK1.5起,Util包就提供了ExecutorService线程池的实现,主要目的是为了重复利用线程,提高系统的效率。 二、线程池的原理线程池,就好比有一个大池子,里面装着已经创建好的线程,当有任务交给线程池执行的话,池中的某个线程会执行该任务。如果任务量太大,而池中的线程又不够的情况下,则需要重新扩充新的线程到线程池中,但是数量是有限的,因为池子是有容量的,不能无限去扩充。当任务比较少的时候,池中的线程会自动回收,不然占着不必要的系统资源。为了能够异步去提交任务和缓冲未被处理的任务,需要有一个任务队列。 问题:完整的线程池需要包含哪些东西???
三、线程池的实现我们通过写代码的形式来实现一个简单的ThreadPool(线程池),虽然简单,但是功能基本具备。我们先来看一下线程的实现类图。 线程池实现类图.png 1.ThreadPool主要定义了ThreadPool应具备的基本操作和方法 public interface ThreadPool {// 提交任务到线程池void execute(Runnable runnable);// 关闭线程池void shutdown();// 获取线程池的初始化大小int getInitSize();// 获取线程池最大的线程数int getMaxSize();// 获取线程池的核心线程数量int getCoreSize();// 获取线程池中用于缓存队列任务的大小int getQueueSize();// 获取线程池中活跃线程的数量int getActiveCount();// 查看线程池是否已经被shutdownboolean isShutdown();} 2.RunnableQueueRunnableQueue主要存放提交的Runnable,该Runnable是一个BlockedQueue,并有limit限制。 package com.lntu.zlt;public interface RunnableQueue {// 将任务提交到队列中,有新的任务进来时首先会offer到队列中void offer(Runnable runnable);// 工作线程通过take()方法获取Runnable,从队列中获取相应的任务。Runnable take();// 获取任务队列中当前Runnable的数量int size(); } 3.ThreadFactoryThreadFactory提供了创建线程的接口,个性化设置Thread,比如加入到哪个Group里面,优先级,Thread名字。 package com.lntu.zlt;//创建线程的工厂 public interface ThreadFactory {// 用于创建线程Thread createThread(Runnable runnable); } 4.DenyPolicyDenyPolicy主要用于当Queue中的Runnable达到了limit上限的话,决定采用哪种策略通知提交者。 package com.lntu.zlt;public interface DenyPolicy {void reject(Runnable runnable, ThreadPool threadPool);// 该策略会直接将任务丢弃class DiscardDenyPolicy implements DenyPolicy { public void reject(Runnable runnable, ThreadPool threadPool) { // TODO Auto-generated method stub // do nothing }}// 该拒绝策略会向任务提交者抛出异常class AbortDenyPolicy implements DenyPolicy { public void reject(Runnable runnable, ThreadPool threadPool) { // TODO Auto-generated method stub throw new RunnableDenyException('The runnable' + runnable + 'will be abort'); }}// 该拒绝策略会使任务在提交者所在的线程中执行任务class RunnerDenyPolicy implements DenyPolicy { public void reject(Runnable runnable, ThreadPool threadPool) { // TODO Auto-generated method stub if (!threadPool.isShutdown()) { runnable.run(); } }} } 5.RunnableDenyExceptionRunnableDenyException是RuntimeException的子类,他主要通知任务的提交者,任务队列已经无法再接收新的任务。 package com.lntu.zlt;public class RunnableDenyException extends RuntimeException {public RunnableDenyException(String message) { // TODO Auto-generated constructor stub super(message);}} 6.InternalTaskInternalTask是Runnable接口的实现,那么大家应该能够知道他是干嘛的了。该类会读取RunnableQueue,然后不断从queue中读取出某个Runnable,然后执行Runnable的run方法 package com.lntu.zlt;public class InternalTask implements Runnable {private final RunnableQueue runnableQueue;private volatile boolean running = true;public InternalTask(RunnableQueue runnableQueue) { this.runnableQueue = runnableQueue;}public void run() { // 如果当前任务为running并且没有被中断,则其不断地从queue中获取runnable,然后执行润方法 while (running && !Thread.currentThread().isInterrupted()) { try { Runnable task = runnableQueue.take(); task.run(); } catch (InterruptedException e) { // TODO: handle exception running = false; break; } }}// 停止当前任务,主要会在线程池的shutdown方法中使用public void stop() { this.running = false;}} 四、线程池面试题这块转子一个简书作者,他这篇帖子写的比较细。
|
|
来自: 昵称60891057 > 《Java》