美文网首页
并发之线程池(二)

并发之线程池(二)

作者: 简楼 | 来源:发表于2021-04-14 19:40 被阅读0次

前言

使用过线程池的我们都知道,创建线程池尽量使用 ThreadPoolExecutor
小提一句,在springboot中推荐使用 ThreadPoolTaskExecutor,该方法是对 ThreadPoolExecutor进行了再一次封装;

image.png

那么为什么要使用 ThreadPoolExecutor创建线程池呢?
在此之前,我们先了解下 Executors 创建线程池的特点;

固定数目线程的线程池:newFixedThreadPool

源码:

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

特点:

  • 核心线程数和最大线程数大小一样
  • keepAliveTime为0L,代表多余的线程立刻终止
  • 阻塞队列为无界队列LinkedBlockingQueue

工作流程

newFixedThreadPool工作流程.png

注意:使用无界队列的线程池会导致内存飙升,因为newFixedThreadPool使用了无界的阻塞队列LinkedBlockingQueue,如果线程获取一个任务后,任务的执行时间比较长,会导致队列的任务越积越多,导致机器内存使用不停飙升, 最终导致OOM;

使用场景

newFixedThreadPool 适用于处理CPU密集型的任务,确保CPU在长期被工作线程使用的情况下,尽可能的少的分配线程,即适用执行长期的任务;

可缓存线程的线程池:newCachedThreadPool

源码:

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

特点:

  • 核心线程数为0
  • 全部都是非核心线程,最大线程数为Integer.MAX_VALUE
  • 阻塞队列是SynchronousQueue(最多只能存在一个元素,有新的任务则阻塞等待)
  • 非核心线程空闲存活时间为60秒

工作流程

newCachedThreadPool工作流程.png

使用场景

用于并发执行大量短期的小任务;

单线程的线程池:newSingleThreadExecutor

源码:

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

特点:

  • 核心线程数,最大线程数均为1,也就是每次只能有一个线程存活
  • 阻塞队列是LinkedBlockingQueue(先进先出原则,所以保证了任务的按顺序逐一进行)
  • keepAliveTime为0

工作流程

newSingleThreadExecutor工作流程.png

使用场景

适用于串行执行任务的场景,一个任务一个任务地执行;

定时及周期执行的线程池:newScheduledThreadPool

源码:

public ScheduledThreadPoolExecutor(int corePoolSize,
                                       ThreadFactory threadFactory) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue(), threadFactory);
    }

特点:

  • 最大线程数为Integer.MAX_VALUE
  • 阻塞队列是DelayedWorkQueue
  • keepAliveTime为0
  • scheduleAtFixedRate() :按某种速率周期执行
  • scheduleWithFixedDelay():在某个延迟后执行

工作流程

newScheduledThreadPool工作流程.png

使用场景

定时和周期性任务场景,需要限制线程数量的场景;

总结

这几种常用的线程池创建,在参数设置上,各有利弊,并不一定适合自己当前的系统,弊端的话,阿里的java规范已经很清楚的告诉我们了;
同时使用以上的创建方式是不够灵活的,所以我们在使用线程时尽量使用ThreadPoolExecutor去创建线程池,按照自己系统的配置去合理设置。

相关文章

  • 并发之线程池(二)

    前言 使用过线程池的我们都知道,创建线程池尽量使用 ThreadPoolExecutor;小提一句,在spring...

  • JUC学习笔记(四)—线程池

    线程池【死磕Java并发】—–J.U.C之线程池:ThreadPoolExecutor 池化技术的好处1、降低资源...

  • ThreadPoolExecutor

    参考文章:Java并发学习之线程池ThreadPoolExecutor的小结并发番@ThreadPoolExecu...

  • Java并发 - 并发编程实战

    Java并发 - 线程Java并发 - 线程池Java并发 - Executor/ExecutorService/...

  • 线程池的原理和AsyncTask

    线程池 1.什么是线程池?为什么要用线程池? Java中的线程池是运用场景最多的并发框架,几乎所有需要异步或并发执...

  • 提纲

    一、数据结构: 二、线程并发: 2.1 线程池; 2.2 AQS系列; 2.3 CAS; 2.4 synchron...

  • 线程

    Java 并发编程:线程池的使用 Java 并发编程:线程池的使用java 多线程核心技术梳理 (附源码) 本文对...

  • 探索 Android 多线程 - 1 AsyncTask

    探索 Android 多线程 - 1 AsyncTask 前言 并发(1) -- 线程与线程池并发(2) -- s...

  • 并发整理(一)— Java并发底层原理

    现已全部整理完,其他两篇并发整理(二)— Java线程与锁并发整理(三)— 并发集合类与线程池 本篇主要是底层的东...

  • 04 线程池原理与AsyncTask

    1 什么是线程池?为什么要用线程池? Java中的线程池是运用场景最多的并发框架,几乎所有需要异步或并发执行任务的...

网友评论

      本文标题:并发之线程池(二)

      本文链接:https://www.haomeiwen.com/subject/glellltx.html