• Java线程池ThreadPoolExecutor&Executors


    一、先看看传统的开启线程

    new Thread(new Runnable() {
        @Override
        public void run() {
        }
    }).start();

    缺点:

    1、每次new Thread新建对象性能差。

    2、线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom。

    3、缺乏更多功能,如定时执行、定期执行、线程中断。

    二、在看看ThreadPoolExecutor

    构造函数:

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

    参数说明:

    corePoolSize:线程池核心线程数(平时保留的线程数)
    maximumPoolSize:线程池最大线程数(当workQueue都放不下时,启动新线程,最大线程数)
    keepAliveTime:超出corePoolSize数量的线程的保留时间。
    unit:keepAliveTime单位
    workQueue:阻塞队列,存放来不及执行的线程
      ArrayBlockingQueue:构造函数一定要传大小
      LinkedBlockingQueue:构造函数不传大小会默认为(Integer.MAX_VALUE ),当大量请求任务时,容易造成 内存耗尽。
      SynchronousQueue:同步队列,一个没有存储空间的阻塞队列 ,将任务同步交付给工作线程。
      PriorityBlockingQueue : 优先队列
    threadFactory:线程工厂
    handler:饱和策略
      AbortPolicy(默认):直接抛弃
      CallerRunsPolicy:用调用者的线程执行任务
      DiscardOldestPolicy:抛弃队列中最久的任务
      DiscardPolicy:抛弃当前任务

    划重点:

    1、当线程池小于corePoolSize时,新提交任务将创建一个新线程执行任务,即使此时线程池中存在空闲线程。
    2、当线程池达到corePoolSize时,新提交任务将被放入workQueue中,等待线程池中任务调度执行
    3、当workQueue已满,且maximumPoolSize>corePoolSize时,新提交任务会创建新线程执行任务
    4、当提交任务数超过maximumPoolSize时,新提交任务由RejectedExecutionHandler处理
    5、当线程池中超过corePoolSize线程,空闲时间达到keepAliveTime时,关闭空闲线程
    6、当设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize线程空闲时间达到keepAliveTime也将关闭

    三、Executors可创建预定义的线程池

    1、FixedThreadPool:创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

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

    特点:

    1)、corePoolSize与maximumPoolSize相等,即其线程全为核心线程,是一个固定大小的线程池,是其优势;
    2)、keepAliveTime = 0 该参数默认对核心线程无效,而FixedThreadPool全部为核心线程;
    3)、workQueue 为LinkedBlockingQueue(无界阻塞队列),队列最大值为Integer.MAX_VALUE。如果任务提交速度持续大余任务处理速度,会造成队列大量阻塞。因为队列很大,很有可能在拒绝策略前,内存溢出。是其劣势;
    4)、FixedThreadPool的任务执行是无序的;

    适用场景:可用于Web服务瞬时削峰,但需注意长时间持续高峰情况造成的队列阻塞。

    2、CachedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

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

    特点:

    1)、corePoolSize = 0,maximumPoolSize = Integer.MAX_VALUE,即线程数量几乎无限制;
    2)、keepAliveTime = 60s,线程空闲60s后自动结束。
    3)、workQueue 为 SynchronousQueue 同步队列,这个队列类似于一个接力棒,入队出队必须同时传递,因为CachedThreadPool线程创建无限制,不会有队列等待,所以使用SynchronousQueue;

    适用场景:快速处理大量耗时较短的任务,如Netty的NIO接受请求时,可使用CachedThreadPool。

    3、SingleThreadExecutor:创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

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

    4、ScheduledThreadPool:创建一个定长线程池,支持定时及周期性任务执行。

        public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
            return new ScheduledThreadPoolExecutor(corePoolSize);
        }

    代码样例:

    public class Test {
        private ExecutorService cachePool = Executors.newCachedThreadPool();
    
        private void test() {
            for (int i = 0; i < 10; i++) {
                cachePool.execute(new Job());
            }
            cachePool.shutdown();
        }
    
        class Job implements Runnable {
            @Override
            public void run() {
                System.out.println("执行任务");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                }
            }
        }
    
        public static void main(String[] args) {
            new ExecutorServiceTest().test();
        }
    }

    参考:

    https://www.jianshu.com/p/f030aa5d7a28

    https://segmentfault.com/a/1190000015368896?utm_source=tag-newest

  • 相关阅读:
    5-python基础—获取某个目录下的文件列表(适用于任何系统)
    Automated, Self-Service Provisioning of VMs Using HyperForm (Part 1) (使用HyperForm自动配置虚拟机(第1部分)
    CloudStack Support in Apache libcloud(Apache libcloud中对CloudStack支持)
    Deploying MicroProfile-Based Java Apps to Bluemix(将基于MicroProfile的Java应用程序部署到Bluemix)
    Adding Persistent Storage to Red Hat CDK Kit 3.0 (在Red Hat CDK Kit 3.0添加永久性存储)
    Carve Your Laptop Into VMs Using Vagrant(使用Vagran把您笔记本电脑刻录成虚拟机)
    使用Python生成一张用于登陆验证的字符图片
    Jupyter notebook的安装方法
    Ubuntu16.04使用Anaconda5搭建TensorFlow使用环境 图文详细教程
    不同时区的换算
  • 原文地址:https://www.cnblogs.com/zhi-leaf/p/10548509.html
Copyright © 2020-2023  润新知