java ThreadPoolExecutor 线程池使用

package com.javaitem.college.thread.action;

/**

 *  多线程测试,
 *  线程池测试 1 自动创建线程池( aliy代码检测不建议 ),2手动创建线程池( aliy代码检测建议 )
 *  ThreadPoolExecutor类提供了4种构造方法,可根据需要来自定义一个线程池。
 */

import cn.hutool.core.date.DateUtil;
import cn.hutool.http.HttpUtil;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;

    public class testThreadPool {

        private Map testMap = new HashMap<>();

        public  void modifytestMap(Map testMap){
            this.testMap  = testMap;
        }
        public  Map getmodifytestMap(){
            return  this.testMap  ;
        }

   /* public static void main(String[] args) {

        testThreadPool tp = new testThreadPool();
      // 1  自动创建线程池 ,aliy代码检测最好手工创建进程池

*//*
        testThreadPool tp = new testThreadPool();
        ExecutorService exec = Executors.newCachedThreadPool();
        for (int i = 0; i < 5; i++) { //5个任务
            exec.submit(new Runnable() {
                @Override
                public void run() {
                   /****要执行的内容***** /
                    Map testMap = tp.getmodifytestMap();
                     testMap.put("key"+ Thread.currentThread().getName(),"1");
                 //  System.out.println(Thread.currentThread().getName()+" doing task");
                }
            });
        }
        exec.shutdown();  //关闭线程池
        Gson g = new Gson();
        System.out.println(g.toJson(tp.getmodifytestMap()));
*//*


        // 2  手工创建多线程
        Gson g = new Gson();
       Console.log(g.toJson(tp.getmodifytestMap()) );
       createThreadPool(tp);

       Console.log(g.toJson(tp.getmodifytestMap()));
    }
*/


        /***
         *
         * public ThreadPoolExecutor(    int corePoolSize,
         *                               int maximumPoolSize,
         *                               long keepAliveTime,
         *                               TimeUnit unit,
         *                               BlockingQueue<Runnable> workQueue,
         *                               ThreadFactory threadFactory,
         *                               RejectedExecutionHandler handler) {
         *         // 省略...
         *     }
         *
         *
         * 1、共7个参数如下:
         * (1)corePoolSize:核心线程数,线程池中始终存活的线程数。
         * (2)maximumPoolSize: 最大线程数,线程池中允许的最大线程数。
         * (3)keepAliveTime: 存活时间,线程没有任务执行时最多保持多久时间会终止。
         * (4)unit: 单位,参数keepAliveTime的时间单位,7种可选。
         * 参数  描述
         * TimeUnit.DAYS   天
         * TimeUnit.HOURS  小时
         * TimeUnit.MINUTES    分
         * TimeUnit.SECONDS    秒
         * TimeUnit.MILLISECONDS   毫秒
         * TimeUnit.MICROSECONDS   微妙
         * TimeUnit.NANOSECONDS    纳秒
         *
         * (5)workQueue: 一个阻塞队列,用来存储等待执行的任务,均为线程安全,7种可选。
         *
         * 参数  描述
         * ArrayBlockingQueue  一个由数组结构组成的有界阻塞队列。
         * LinkedBlockingQueue 一个由链表结构组成的有界阻塞队列。
         * SynchronousQueue    一个不存储元素的阻塞队列,即直接提交给线程不保持它们。
         * PriorityBlockingQueue   一个支持优先级排序的无界阻塞队列。
         * DelayQueue  一个使用优先级队列实现的无界阻塞队列,只有在延迟期满时才能从中提取元素。
         * LinkedTransferQueue 一个由链表结构组成的无界阻塞队列。与SynchronousQueue类似,还含有非阻塞方法。
         * LinkedBlockingDeque 一个由链表结构组成的双向阻塞队列。
         * 较常用的是LinkedBlockingQueue和Synchronous。线程池的排队策略与BlockingQueue有关。
         *
         * (6)threadFactory: 线程工厂,主要用来创建线程,默及正常优先级、非守护线程。
         *
         * (7)handler:拒绝策略,拒绝处理任务时的策略,4种可选,默认为AbortPolicy。
         *
         * 参数  描述
         * AbortPolicy 拒绝并抛出异常。
         * CallerRunsPolicy    重试提交当前的任务,即再次调用运行该任务的execute()方法。
         * DiscardOldestPolicy 抛弃队列头部(最旧)的一个任务,并执行当前任务。
         * DiscardPolicy   抛弃当前任务。
         *
         *2、顺便说下线程池的执行规则如下:
         *
         * (1)当线程数小于核心线程数时,创建线程。
         * (2)当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列。
         * (3)当线程数大于等于核心线程数,且任务队列已满:
         *      若线程数小于最大线程数,创建线程。
         *      若线程数等于最大线程数,抛出异常,拒绝任务。
         *
         *
         * 效果:
         * 2021-08-25 15:50:29 pool-1-thread-4 8
         * 2021-08-25 15:50:29 pool-1-thread-2 1
         * 2021-08-25 15:50:29 pool-1-thread-1 0
         * 2021-08-25 15:50:29 pool-1-thread-5 9
         * 2021-08-25 15:50:29 pool-1-thread-3 7
         * 2021-08-25 15:50:31 pool-1-thread-3 3
         * 2021-08-25 15:50:31 pool-1-thread-2 2
         * 2021-08-25 15:50:31 pool-1-thread-4 4
         * 2021-08-25 15:50:31 pool-1-thread-1 5
         * 2021-08-25 15:50:31 pool-1-thread-5 6
         *
         *   因为核心线程数为2,队列大小为5,存活时间1分钟,所以流程是第0-1号任务来时,陆续创建2个线程,
         *    然后第2-6号任务来时,因为无线程可用,均进入了队列等待,
         *    第7-9号任务来时,没有空闲线程,队列也满了,所以陆续又创建了3个线程。
         *    所以你会发现7-9号任务反而是先执行的。又因为各任务只需要2秒,而线程存活时间有1分钟,所以线程进行了复用,所以总共只创建了5个线程。
         *
         * @param tp
         */



        //手工创建线程池
        private static void createThreadPool(testThreadPool tp) {
            Integer corePoolSize  = 99;
            Integer maxinumPoolSize = 99;
            Integer keepAliveTime = 1;
            Integer capacity = 999;

            ExecutorService executorService = new ThreadPoolExecutor(corePoolSize, maxinumPoolSize,
                    keepAliveTime, TimeUnit.MINUTES, new ArrayBlockingQueue<>(capacity, true),
                    Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
            for (int i = 0; i < 99; i++) {
                final int index = i;
                executorService.execute(() -> {
                    // 获取线程名称,默认格式:pool-1-thread-1

                    System.out.println(DateUtil.now() + " " + Thread.currentThread().getName() + " " + index);
                    String url = "http://10.10.31.194/";
                    HttpUtil.get(url);

                    // 等待2秒
                          /*    try {
                                  Thread.sleep(200);
                              } catch (InterruptedException e) {
                                  e.printStackTrace();
                              }*/
                });
                ThreadPoolExecutor tpe = ((ThreadPoolExecutor) executorService);
                tpe.getQueue().size();//获取队列数量

            }
        }
/**
 *
 * 三、五种方式的优劣比较
 *
 * 说是5种方式的比较,其实就是2种方式的比较,为什么这么说?因为Executors类提供的4种方式,其底层其实都是通过ThreadPoolExecutor类来实现的。换句话说,
 * 就是Executors类工厂通过参数的组合,组装出了上面提到的4种类型线程池供不同场景使用。我们可以通过查看Executors类的源码来看看:
 *
 * 1、newCachedThreadPool
 *
 * 1     public static ExecutorService newCachedThreadPool() {
 * 2         return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
 * 3                                       60L, TimeUnit.SECONDS,
 * 4                                       new SynchronousQueue<Runnable>());
 * 5     }
 *   因为SynchronousQueue队列不保持它们,直接提交给线程,相当于队列大小为0,而最大线程数为Integer.MAX_VALUE,所以线程不足时,
 *    会一直创建新线程,等到线程空闲时,又有60秒存活时间,从而实现了一个可缓存的线程池。
 *
 *
 *
 * 2、newFixedThreadPool
 *
 * 1     public static ExecutorService newFixedThreadPool(int nThreads) {
 * 2         return new ThreadPoolExecutor(nThreads, nThreads,
 * 3                                       0L, TimeUnit.MILLISECONDS,
 * 4                                       new LinkedBlockingQueue<Runnable>());
 * 5     }
 *   因为核心线程数与最大线程数相同,所以线程池的线程数是固定的,而且没有限制队列的大小,所以多余的任务均会被放到队列排队,从而实现一个固定大小,可控制并发数量的线程池。
 *
 *
 *
 * 3、newScheduledThreadPool
 *
 *
 * 1     public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
 * 2         return new ScheduledThreadPoolExecutor(corePoolSize);
 * 3     }
 * 4
 * 5     public ScheduledThreadPoolExecutor(int corePoolSize) {
 * 6         super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
 * 7               new DelayedWorkQueue());
 * 8     }
 *
 *   因为使用了延迟队列,只有在延迟期满时才能从中提取到元素,从而实现定时执行的线程池。而周期性执行是配合上层封装的其他类来实现的,
 *   可以看ScheduledExecutorService类的scheduleAtFixedRate方法。
 *
 *
 *
 * 4、newSingleThreadExecutor
 *
 *
 * 1     public static ExecutorService newSingleThreadExecutor() {
 * 2         return new FinalizableDelegatedExecutorService
 * 3             (new ThreadPoolExecutor(1, 1,
 * 4                                     0L, TimeUnit.MILLISECONDS,
 * 5                                     new LinkedBlockingQueue<Runnable>()));
 * 6     }
 *
 *   因为核心线程数与最大线程数相同,均为1,所以线程池的线程数是固定的1个,而且没有限制队列的大小,
 *     所以多余的任务均会被放到队列排队,从而实现一个单线程按指定顺序执行的线程池。
 *
 *
 *
 *  虽然看上去Executors类的封装,可以简化我们的使用,但事实上,阿里代码规范《阿里巴巴Java开发手册》中明确不建议使用Executors类提供的这4种方法:
 *
 *
 * 【强制】线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
 *
 * Executors返回的线程池对象的弊端如下:
 *
 * FixedThreadPool和SingleThreadPool:允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM。
 *
 * CachedThreadPool和ScheduledThreadPool:允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM。
 *
 *   再回头看看上面的源码,确实如此。所以我们应该使用ThreadPoolExecutor类来创建线程池,根据自己需要的场景来创建一个合适的线程池。
 */


    }

猜你喜欢

转载自blog.csdn.net/zhanglixin999/article/details/120951117