详解 ExecutorService 接口及其实现类 ThreadPoolExecutor

文章目录

    • 1. ExecutorService 接口简介
    • 2. ThreadPoolExecutor
        • 2.1 对各个参数的解读
        • 2.2 任务队列的四种类型
        • 2.3 饱和(拒绝)策略的四种类型
    • 3. newFixedThreadPool
    • 4. newSingThreadExecutor
    • 5. newCachedThreadPool
    • 6. 实现自己的简易版线程池

1. ExecutorService 接口简介

Executor 框架中有两个关键类实现了 ExecutorService 接口,ThreadPoolExecutor 和 ScheduledThreadPoolExecutor

  • Executor 接口: 它是 Executor 框架的基础,只提供了一个execute() 方法,用于执行提交的 Runnable 实例
  • ExecutorService 接口:继承了 Executor 接口,包含了大量的方法控制任务的进度和管理服务的终止。使用此接口,您可以提交要执行的任务,还可以使用返回的Future实例控制其执行。
  • ThreadPoolExecutor:是线程池的核心实现类,用来执行被提交的任务。
  • ScheduledThreadPoolExecutor:可以在给定的延迟后运行命令,或者定期执行命令。

2. ThreadPoolExecutor

ThreadPoolExecutor有四个构造方法,这是其中之一,其他构造方法都是在此基础上传入默认参数

 public ThreadPoolExecutor(int corePoolSize,
                           int maximumPoolSize,
                           long keepAliveTime,
                           TimeUnit unit,
                           BlockingQueue<Runnable> workQueue,
                           ThreadFactory threadFactory,
                           RejectedExecutionHandler handler)

2.1 对各个参数的解读

corePoolSize: 池中所保存的核心线程数,包括空闲线程。

maximumPoolSize:池中允许创建的最大线程数。当workqueue使用无界队列LinkedBlockingQueue等时,此参数无效。

keepAliveTime:当前线程池线程总数大于核心线程数时,keepAliveTime 为多余的空闲线程等待新任务的最长时间。

unit:参数的时间单位

workQueue:任务队列,如果当前线程池达到核心线程数时,且当前所有线程都处于活动状态,则将新加入的任务放到此队列中。当任务队列满了之后,且工作线程介于核心线程数和最大线程数之间,则创建新的线程执行任务。

threadFactory:设置执行程序创建新线程时使用的工厂。

handler: 饱和策略,当队列和线程池都满了,必须采取一种策略处理提交的任务,默认直接抛出异常

2.2 任务队列的四种类型

  • ArrayBlockingQueue:基于数组结构有界队列,FIFO原则对任务进行排序,队列满了之后的任务,调用拒绝策略。
  • LinkedBlockingQueue:基于链表结构的无界队列,FIFO原则对任务进行排序。
  • SynchronousQueue:直接将任务提交给线程而不是将它加入到队列,实际上此队列是空的。每个插入的操作必须等到另一个调用移除的操作;如果新任务来了线程池没有任何可用线程处理的话,则调用拒绝策略。
  • PriorityBlockingQueue:具有优先级的队列的有界队列,可以自定义优先级;默认是按自然排序。

2.3 饱和(拒绝)策略的四种类型

  • AborttPolicy:直接抛出异常
  • CallerRunsPolicy:只用调用者所在的线程执行任务
  • DiscardOldestPolicy:丢弃队列里最老的任务,用来执行当前的任务
  • DiscardPolicy:不进行处理,直接丢弃掉

3. newFixedThreadPool

newFixedThreadPool 被称为可重用固定线程的线程池,下面是其源代码

 public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

newFixedThreadPool 的 corePoolSize 和 maximumPoolSize都被设置为 nThreads,keepAliveTime被设置为 0L,意味着如果线程数超过传入的参数 nThread 时,多余的空闲线程会被立即终止。

在这里因为使用了 LinkedBlockingQueue 这个无界队列,当线程数达到 nThreads 后,新任务会在无界队列中等到,无界队列不满就不会创建新的线程,所以 maximumPoolSize 是一个无效的参数。而且永远不会拒绝任务。

4. newSingThreadExecutor

newSingThreadExecutor 是使用单个 worker 线程的 Executor,源码实现如下

public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

newSingThreadExecutor 的 corePoolSize 和 maximumPoolSize 都被设置为 1 , 其余参数与 newFixedThreadPool一样,因此可看做线程数为1 的 newFixedThreadPool。

5. newCachedThreadPool

newCachedThreadPool 是一个根据需要创建新线程的线程池,实现源码如下

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

newCachedThreadPool的 corePoolSize 被设置为0,maximunPoolSize被设置为 Integer.MAX_VALUE,说明其核心线程池为空,最大线程池没有界限。keepAliveTime被设置为 60L,意味着空闲线程等待新任务的最长时间为60秒,超过60秒就会被终止。同时使用了 SynchronousQueue 这个没有容量的阻塞队列,意味着当主线程提交任务的速率大于线程池处理任务的速率时,newCachedThreadPool 会直接创建新线程来处理新任务,降低了线程的重复利用率。

6. 实现自己的简易版线程池

构造函如图
详解 ExecutorService 接口及其实现类 ThreadPoolExecutor_第1张图片

第一个参数是核心线程数大小,第二个参数是最大线程数大小,第三个参数是空闲线程最大存活时间,单位为秒。第四个参数是拒绝策略。线程池的任务队列默认大小为 1000,当提交的线程数大小超过 1000 时,则执行拒绝策略。

package multithread;

import java.util.*;

public class SimpleThreadPool extends Thread{
   private int coreSize; //核心线程数

   private int maxSize; //最大线程数

   private int curSize;//当前线程池大小

   private int queueSize; //任务队列大小

   private static int taskSize = 0; //统计提交的线程数

   private long keepActiveTime;

   private volatile boolean destroy = false;

   private static final int DEFAULT_CORE_SIZE = 5; //默认核心线程数

   private static final int DEFAULT_MAX_SIZE = 10; //默认最大线程数

   private static final int DEFAULT_QUEUE_SIZE = 100; //默认任务队列大小

   private final ThreadGroup GROUP = new ThreadGroup("Pool_Group"); //线程组名

   private final String PRE_NAME = "SimpleThreadPool-"; //线程名前缀

   private static int index = 0;

   private final static LinkedList<Runnable> TASK_QUEUE = new LinkedList<>();

   private final static List<WorkTask> THREAD_QUEUE = new ArrayList<>();

   private DiscardPolicy discardPolicy;//拒绝策略

   //默认拒绝策略
   private final static DiscardPolicy DEFAULT_DISCARD_POLICY = () ->{
       System.out.println("Discard this task");
   };

   public SimpleThreadPool() {
       this(DEFAULT_CORE_SIZE, DEFAULT_MAX_SIZE, 0, DEFAULT_DISCARD_POLICY);
   }
   
   public SimpleThreadPool(int coreSize, int maxSize, long keepActiveTime, DiscardPolicy discardPolicy) {
       this.coreSize = coreSize;
       this.maxSize = maxSize;
       this.keepActiveTime = keepActiveTime * 1000L;
       this.queueSize = DEFAULT_QUEUE_SIZE;
       this.discardPolicy = discardPolicy;

       init();
   }

   private void init() {
       for (int i = 0; i < coreSize; i++)
           createWorkTask();

       this.curSize = coreSize;
       this.start();
   }

   private void createWorkTask() {
       WorkTask task = new WorkTask(GROUP, PRE_NAME + ++index);
       task.start();
       THREAD_QUEUE.add(task);
   }

   @Override
   public void run() {
       while (!destroy) {
           System.out.printf("Pool#coreSize:%d,maxSize:%d,currentSize:%d,QueueSize:%d\n\n",
                   this.coreSize, this.maxSize, this.curSize, TASK_QUEUE.size());

           try {
               Thread.sleep(5_000L);
               // thread incremeneted
               if (TASK_QUEUE.size() > 0 && curSize < maxSize) {
                   for (int i = coreSize; i < maxSize; i++) {
                       createWorkTask();
                   }
                   System.out.println("The pool incremented to max.");
                   curSize = maxSize;
               }
               
               // thread reduce
               synchronized (THREAD_QUEUE) {
                   if (TASK_QUEUE.isEmpty() && curSize > coreSize) {
                       Thread.sleep(keepActiveTime);
                       System.out.println("===========reduce===========");
                       int releaseSize = curSize - coreSize;
                       Iterator<WorkTask> it = THREAD_QUEUE.iterator();
                       while (it.hasNext()) {
                           if (releaseSize <= 0)
                               break;
                           WorkTask task = it.next();
                           task.close();
                           task.interrupt();
                           it.remove();
                           releaseSize--;
                       }
                       curSize = coreSize;
                   }
               }
           } catch(InterruptedException e) {
               e.printStackTrace();
           }
       }
   }
   
   public void submit(Runnable runnable) {
       if (destroy)
           throw new IllegalStateException("The thread pool already destroy and not allow submit task.");

       synchronized (TASK_QUEUE) {
           if (TASK_QUEUE.size() > queueSize)
               discardPolicy.discard();

           if (taskSize > coreSize) {
               TASK_QUEUE.addLast(runnable);
               TASK_QUEUE.notifyAll();
           }
           taskSize++;
       }
   }

   public void shutdown() throws InterruptedException{
       while (!TASK_QUEUE.isEmpty()) {
           try {
               Thread.sleep(50);
           } catch (Exception e) {
               e.printStackTrace();
           }
       }
       synchronized (THREAD_QUEUE) {
           int initSize = THREAD_QUEUE.size();
           while (initSize > 0) {
               for (WorkTask task : THREAD_QUEUE) {
                   if (task.taskState == TaskState.BLOCKED) {
                       task.interrupt();
                       task.close();
                       initSize--;
                   } else {
                       Thread.sleep(10);
                   }
               }
           }
       }
       System.out.println("active: " + GROUP.activeCount() + "  THREAD_QUEUE size: " + THREAD_QUEUE.size());
       this.destroy = true;
       System.out.println("The thread pool disposed.");
   }


   private enum TaskState {
       FREE, RUNNING, BLOCKED, DEAD
   }

   public static class DiscardException extends RuntimeException {

       public DiscardException(String message) {
           super(message);
       }
   }

   public interface DiscardPolicy {
       void discard() throws DiscardException;
   }

   private static class WorkTask extends Thread {
       private volatile TaskState taskState = TaskState.FREE;

       public WorkTask(ThreadGroup group, String name) {
           super(group, name);
       }

       public TaskState getTaskState() {
           return this.taskState;
       }

       @Override
       public void run() {
           OUTER: while (taskState != TaskState.DEAD) {
               Runnable runnable;
               synchronized (TASK_QUEUE) {
                   while (TASK_QUEUE.isEmpty()) {
                       try {
                           taskState = TaskState.BLOCKED;
                           TASK_QUEUE.wait();
                       } catch (InterruptedException e) {
                           System.out.println("Closed.");
                           break OUTER;
                       }

                   }
                   runnable = TASK_QUEUE.removeFirst();
               }

               if (runnable != null) {
                   this.taskState = TaskState.RUNNING;
                   runnable.run();
                   this.taskState = TaskState.FREE;
               }
           }
       }

       public void close() {
           this.taskState = TaskState.DEAD;
       }
   }

   public boolean isDestroy() {
       return this.destroy;
   }

   public static void main(String[] args) throws InterruptedException {
       SimpleThreadPool threadPool = new SimpleThreadPool();
       for (int i = 0; i < 50; i++) {
           threadPool.submit(() -> {
               System.out.println("The runnable be serviced by " + Thread.currentThread() + " start.");
               try {
                   Thread.sleep(3000);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
               System.out.println("The runnable be serviced by " + Thread.currentThread() + " finished.");
           });
       }

       Thread.sleep(5_000L);
       threadPool.shutdown();
   }
}

你可能感兴趣的:(Java基础,Executor,线程池,ExecutorService)