以前多线程也常用,这次因需再页面上用到多线程,如下图,总结下,有需要的朋友可以参考下。
线程池官方定义不说了,通俗说下:池子的概念,事先(预定义)创建后,后续的线程可以直接从池子中拿,好处:
(1)来创建线程比较消耗资源,不用重复创建;
(2)池子事先定义好,避免无节制创建线程,导致系统出现不可预测风险。
采用jdk自带的线程池创建方式,jdk1.5开始提供,在java.util.concurrent 的包下面。
表面上有两种创建方式,其实一种。
(1)一种是采用new ThreadPoolExecutor进行创建;
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
(2)一种是采用Executors.newFixedThreadPool(3),不过还是调用的new ThreadPoolExecutor进行的线程池创建,赋值了几个默认参数而已。
new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
一共有 7 个参数:
核心线程数,当有任务进来的时候,如果当前线程数还未达到 corePoolSize 个数,则创建核心线程,核心线程有几个特点:
1、当线程数未达到核心线程最大值的时候,新任务进来,即使有空闲线程,也不会复用,仍然新建核心线程;2、核心线程一般不会被销毁,即使是空闲的状态,但是如果通过方法 allowCoreThreadTimeOut(boolean value) 设置为 true 时,超时也同样会被销毁;3、生产环境首次初始化的时候,可以调用 prestartCoreThread() 方法来预先创建所有核心线程,避免第一次调用缓慢;
除了有核心线程外,有些策略是当核心线程完全无空闲的时候,还会创建一些临时的线程来处理任务,maximumPoolSize 就是核心线程 + 临时线程的最大上限。临时线程有一个超时机制,超过了设置的空闲时间没有事儿干,就会被销毁。
这个就是上面两个参数里所提到的超时时间,也就是线程的最大空闲时间,默认用于非核心线程,通过 allowCoreThreadTimeOut(boolean value) 方法设置后,也会用于核心线程。
这个参数配合上面的 keepAliveTime ,指定超时的时间单位,秒、分、时等。
等待执行的任务队列,如果核心线程没有空闲的了,新来的任务就会被放到这个等待队列中。
它是一个接口,用于实现生成线程的方式、定义线程名格式、是否后台执行等等,可以用 Executors.defaultThreadFactory() 默认的实现即可,也可以用 Guava 等三方库提供的方法实现,如果有特殊要求的话可以自己定义。它最重要的地方应该就是定义线程名称的格式,便于排查问题了吧。
当没有空闲的线程处理任务,并且等待队列已满(当然这只对有界队列有效),再有新任务进来的话,就要做一些取舍了,而这个参数就是指定取舍策略的,有下面四种策略可以选择:
ThreadPoolExecutor.AbortPolicy:直接抛出异常,这是默认策略;
ThreadPoolExecutor.DiscardPolicy:直接丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后将新来的任务加入等待队列
ThreadPoolExecutor.CallerRunsPolicy:由线程池所在的线程处理该任务,比如在 main 函数中创建线程池,如果执行此策略,将有 main 线程来执行该任务
package com.yutong.laowang.test; public class ThreadTest extends Thread{ @Override public void run() { System.out.println("软件老王:" +Thread.currentThread().getName()); } }
private static void test4() { Executor mExecutor = Executors.newFixedThreadPool(3); for (int i = 0; i < 10; i++) { Thread thread = new ThreadTest(); mExecutor.execute(thread); } }
结果:
软件老王:pool-2-thread-2 软件老王:pool-2-thread-3 软件老王:pool-2-thread-1 软件老王:pool-2-thread-3 软件老王:pool-2-thread-2 软件老王:pool-2-thread-1 软件老王:pool-2-thread-3 软件老王:pool-2-thread-2 软件老王:pool-2-thread-3 软件老王:pool-2-thread-1
private static void test3() { int poolSize = 5; int queueSize = 100; ExecutorService executorService = new ThreadPoolExecutor(poolSize, poolSize, 0L, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(queueSize), new ThreadPoolExecutor.AbortPolicy()); for (int i=0;i<10;i++) { executorService.submit(new ThreadTest()); } }
结果:
软件老王:pool-2-thread-1 软件老王:pool-2-thread-3 软件老王:pool-2-thread-4 软件老王:pool-2-thread-2 软件老王:pool-2-thread-5 软件老王:pool-2-thread-5 软件老王:pool-2-thread-1 软件老王:pool-2-thread-2 软件老王:pool-2-thread-2 软件老王:pool-2-thread-1
thread.interrupt(); ---有时候不一定能执行成功,一般会结合判断使用,软件老王,例如: 在ThreadTest类中进行判断,默认为false,当满足条件下为true,停用线程。 public volatile boolean exit = false;
I’m 「软件老王」,如果觉得还可以的话,关注下呗,后续更新秒知!欢迎讨论区、同名公众号留言交流!