Java并发编程——线程池Executor

目录

  • 一、线程池`Executor`
    • 1. 传统 `new Thread`的弊端
      • 因此日常使用线程的时候,尽量避免使用`new Thread`去创建线程,从而减少不必要的麻烦和困扰;
    • 2. 线程池的优点
    • 3.线程池(`ThreadPoolExecutor`)的核心类
        • 参数说明:`ThreadPoolExecutor`一共有七个参数,这七个参数配合起来,构成了线程池强大的功能。
    • 4.`corePoolSize`、`maximumPoolSize`、`workQueue` 三者关系
    • 5.线程池的五种状态
    • 6.线程池`ThreadPoolExecutor`的主要方法
  • 二、使用`Executor`创建线程池
          • 注意:`ExecutorService`中只提供了基本的线程池的方法:`submit()`、 `shutdown()`、`shutdownNow()`等;而不支持其他监控方法,如`getTaskCount()`、`getCompleteTaskCount() `等;
    • 1.`Executors.newCachedThreadPool()`方法创建线程池
          •  `Executors.newCachedThreadPool()`其目的是创建一个可缓存的线程池,如果线程池的长度超过了处理的需要,可以灵活回收空闲线程。如果没有可回收的就新建线程。
          • 由此可见,通过使用`Executors` 中的`newCachedThreadPool()`方法创建线程池,其内部实际还是通过`ThreadPoolExecutor`来创建线程池,只不过很多参数都已经被指定好了。
    • 2.`Executors.newFixedThreadPool()`方法创建线程池
          •  其目的是创建定长线程池,可以线程现成的最大并发数,超出在队列等待
    • 3.`Executors.newSingleThreadExecutor()`方法创建线程池
          •  其目的是创建单线程化的线程池,用唯一的一个共用线程执行任务,保证所有任务按指定顺序执行(FIFO、优先级…)
    • 4.`Executors.newScheduledThreadPool()`方法创建线程池
          •  其目的是创建定长线程池,支持定时和周期任务执行;
    • Java并发编程学习系列

一、线程池Executor

1. 传统 new Thread的弊端

  • 每次new Thread 新建对象,性能差;
  • 线程缺乏统一管理,可能无限制的新建线程,相互竞争,可能占用过多的系统资源导致死机或者OOMout of memory内存溢出),这种问题的原因不是因为单纯的new一个Thread,而是可能因为程序的bug或者设计上的缺陷导致不断new Thread造成的。
  • 缺少更多功能,如更多执行、定期执行、线程中断。

因此日常使用线程的时候,尽量避免使用new Thread去创建线程,从而减少不必要的麻烦和困扰;

2. 线程池的优点

  • 重用存在的线程,减少对象创建、消亡的开销,性能好;
  • 可有效控制最大并发线程数,提高系统资源利用率,同时可以避免过多资源竞争,避免阻塞。
  • 提供定时执行、定期执行、单线程、并发数控制等功能。

3.线程池(ThreadPoolExecutor)的核心类

参数说明:ThreadPoolExecutor一共有七个参数,这七个参数配合起来,构成了线程池强大的功能。

  1. corePoolSize:核心线程数量;
  2. maximumPoolSize:线程最大线程数;
  3. workQueue:阻塞队列,存储等待执行的任务,很重要,会对线程池运行过程产生重大影响;
  4. keepAliveTime:线程没有任务执行时最多保持多久时间终止(当线程中的线程数量大于corePoolSize的时候,如果这时没有新的任务提交核心线程外的线程不会立即销毁,而是等待,直到超过keepAliveTime);
  5. unitkeepAliveTime的时间单位;
  6. threadFactory:线程工厂,用来创建线程,有一个默认的工场来创建线程,这样新创建出来的线程有相同的优先级,是非守护线程、设置好了名称);
  7. rejectHandler:当拒绝处理任务时(阻塞队列满)的策略(AbortPolicy默认策略直接抛出异常、CallerRunsPolicy用调用者所在的线程执行任务、DiscardOldestPolicy丢弃队列中最靠前的任务并执行当前任务、DiscardPolicy直接丢弃当前任务)

4.corePoolSizemaximumPoolSizeworkQueue 三者关系

 如果运行的线程数小于corePoolSize的时候,直接创建新线程来处理任务。即使线程池中的其他线程是空闲的。如果运行中的线程数大于corePoolSize且小于maximumPoolSize时,那么只有当workQueue满的时候才创建新的线程去处理任务。如果corePoolSizemaximumPoolSize是相同的,那么创建的线程池大小是固定的。这时有新任务提交,当workQueue未满时,就把请求放入workQueue中。等待空线程从workQueue取出任务。如果workQueue此时也满了,那么就使用另外的拒绝策略参数去执行拒绝策略。

5.线程池的五种状态

Java并发编程——线程池Executor_第1张图片

  • running:能接受新提交的任务,也能处理阻塞队列中的任务
  • shutdown:不能处理新的任务,但是能继续处理阻塞队列中任务
  • stop:不能接收新的任务,也不处理队列中的任务
  • tidying:如果所有的任务都已经终止了,这时有效线程数为0
  • terminated:最终状态

6.线程池ThreadPoolExecutor的主要方法

  • execute():提交任务,交给线程池执行;
  • submit():提交任务,能够返回执行结果 execute+Future
  • shutdown():关闭线程池,等待任务都执行完;
  • shutdownNow():关闭线程池,不等待任务执行完;
  • getTaskCount():线程池已执行和未执行的任务总数;
  • getCompleteTaskCount():已完成的任务数量;
  • getPoolSize():线程池当前的线程数量;
  • getActiveCount():当前线程池中正在执行任务的线程数量;

二、使用Executor创建线程池

注意:ExecutorService中只提供了基本的线程池的方法:submit()shutdown()shutdownNow()等;而不支持其他监控方法,如getTaskCount()getCompleteTaskCount()等;

1.Executors.newCachedThreadPool()方法创建线程池

Executors.newCachedThreadPool()其目的是创建一个可缓存的线程池,如果线程池的长度超过了处理的需要,可以灵活回收空闲线程。如果没有可回收的就新建线程。
  • newCachedThreadPool源码如下所示:
public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}
由此可见,通过使用Executors 中的newCachedThreadPool()方法创建线程池,其内部实际还是通过ThreadPoolExecutor来创建线程池,只不过很多参数都已经被指定好了。
  • 具体使用示例:
@Slf4j
public class ThreadPoolExample1 {

    public static void main(String[] args) {

        ExecutorService executorService = Executors.newCachedThreadPool();

        for (int i = 0; i < 10; i++) {
            final int index = i;
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    log.info("task:{}", index);
                }
            });
        }
        executorService.shutdown();
    }
}

执行结果:

16:12:57.979 [pool-1-thread-9] INFO com.mmall.concurrency.example.threadPool.ThreadPoolExample1 - task:8
16:12:57.985 [pool-1-thread-1] INFO com.mmall.concurrency.example.threadPool.ThreadPoolExample1 - task:0
16:12:57.979 [pool-1-thread-2] INFO com.mmall.concurrency.example.threadPool.ThreadPoolExample1 - task:1
16:12:57.980 [pool-1-thread-4] INFO com.mmall.concurrency.example.threadPool.ThreadPoolExample1 - task:3
16:12:57.980 [pool-1-thread-10] INFO com.mmall.concurrency.example.threadPool.ThreadPoolExample1 - task:9
16:12:57.980 [pool-1-thread-3] INFO com.mmall.concurrency.example.threadPool.ThreadPoolExample1 - task:2
16:12:57.980 [pool-1-thread-6] INFO com.mmall.concurrency.example.threadPool.ThreadPoolExample1 - task:5
16:12:57.979 [pool-1-thread-5] INFO com.mmall.concurrency.example.threadPool.ThreadPoolExample1 - task:4
16:12:57.980 [pool-1-thread-8] INFO com.mmall.concurrency.example.threadPool.ThreadPoolExample1 - task:7
16:12:57.980 [pool-1-thread-7] INFO com.mmall.concurrency.example.threadPool.ThreadPoolExample1 - task:6

Process finished with exit code 0

2.Executors.newFixedThreadPool()方法创建线程池

 其目的是创建定长线程池,可以线程现成的最大并发数,超出在队列等待
  • 源码解读:
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}
  • 具体使用示例:

@Slf4j
public class ThreadPoolExample2 {

    public static void main(String[] args) {

        ExecutorService executorService = Executors.newFixedThreadPool(3);

        for (int i = 0; i < 10; i++) {
            final int index = i;
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    log.info("task:{}", index);
                }
            });
        }
        executorService.shutdown();
    }
}

执行结果同上;

3.Executors.newSingleThreadExecutor()方法创建线程池

 其目的是创建单线程化的线程池,用唯一的一个共用线程执行任务,保证所有任务按指定顺序执行(FIFO、优先级…)
  • 源码解读:
//源码
public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}
  • 使用示例:
@Slf4j
public class ThreadPoolExample3 {

    public static void main(String[] args) {

        ExecutorService executorService = Executors.newSingleThreadExecutor();

        for (int i = 0; i < 10; i++) {
            final int index = i;
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    log.info("task:{}", index);
                }
            });
        }
        executorService.shutdown();
    }
}

执行结果如下:

16:34:57.825 [pool-1-thread-1] INFO com.mmall.concurrency.example.threadPool.ThreadPoolExample3 - task:0
16:34:57.832 [pool-1-thread-1] INFO com.mmall.concurrency.example.threadPool.ThreadPoolExample3 - task:1
16:34:57.832 [pool-1-thread-1] INFO com.mmall.concurrency.example.threadPool.ThreadPoolExample3 - task:2
16:34:57.832 [pool-1-thread-1] INFO com.mmall.concurrency.example.threadPool.ThreadPoolExample3 - task:3
16:34:57.832 [pool-1-thread-1] INFO com.mmall.concurrency.example.threadPool.ThreadPoolExample3 - task:4
16:34:57.832 [pool-1-thread-1] INFO com.mmall.concurrency.example.threadPool.ThreadPoolExample3 - task:5
16:34:57.832 [pool-1-thread-1] INFO com.mmall.concurrency.example.threadPool.ThreadPoolExample3 - task:6
16:34:57.832 [pool-1-thread-1] INFO com.mmall.concurrency.example.threadPool.ThreadPoolExample3 - task:7
16:34:57.832 [pool-1-thread-1] INFO com.mmall.concurrency.example.threadPool.ThreadPoolExample3 - task:8
16:34:57.832 [pool-1-thread-1] INFO com.mmall.concurrency.example.threadPool.ThreadPoolExample3 - task:9

Process finished with exit code 0

执行得到结果与预期得到一致,线程按照顺序依次执行;

4.Executors.newScheduledThreadPool()方法创建线程池

 其目的是创建定长线程池,支持定时和周期任务执行;
  • 源码解读:
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,//此处super指的是ThreadPoolExecutor
          new DelayedWorkQueue());
}
  • 使用示例:
@Slf4j
public class ThreadPoolExample4 {

    public static void main(String[] args) {

        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);

//        executorService.schedule(new Runnable() {
//            @Override
//            public void run() {
//                log.warn("schedule run");
//            }
//        }, 3, TimeUnit.SECONDS);

        executorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                log.warn("schedule run");
            }
        }, 1, 3, TimeUnit.SECONDS);
//        executorService.shutdown();

        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                log.warn("timer run");
            }
        }, new Date(), 5 * 1000);
    }
}

Java并发编程学习系列

如有帮助,烦请点赞收藏一下啦 (◕ᴗ◕✿)

你可能感兴趣的:(Java并发编程,Java并发编程,Excecutor,线程池,创建线程池)