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类来创建线程池,根据自己需要的场景来创建一个合适的线程池。 */ }
java ThreadPoolExecutor 线程池使用
猜你喜欢
转载自blog.csdn.net/zhanglixin999/article/details/120951117
今日推荐
周排行