Java多线程 ThreadPoolExecutor自定义线程池

简介: Java多线程 ThreadPoolExecutor自定义线程池

一、说明


ThreadPoolExecutor



  • 它有多个构造方法来实现自定义创建线程池,以内部线程池的形式对外提供管理任务执行,线程调度,线程池管理等



二、理解


ThreadPoolExecutor


java.util.cocurrent 包下ThreadPoolExecutor类继承AbstractExecutorService


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


  • corePoolSize 核心线程数,默认为0,有任务时将创建线程去执行,当线程数达到corePoolSize时,停止线程创建,将任务放到队列中等待;调用prestartAllCoreThreads()prestartCoreThread()方法,可以预创建线程


  • maximumPoolSize 线程池线程数,当线程数达到核corePoolSize时,如果任务队列已满,线程池会创建新的线程,直到线程数量达到最maxPoolSize


  • keepAliveTime 线程池中超过corePoolSize的空闲线程最大存活时间,超时则销毁,直到线程数量等于corePoolSize


  • TimeUnit keepAliveTime时间单位


  • workQueue 阻塞任务队列,用来存储等待执行的任务


  • threadFactory 线程工厂,可以更改线程的名称,线程组,优先级,守护进程状态等


  • RejectedExecutionHandler 拒绝执行策略,当提交任务数超过maximumPoolSize+workQueue时,再提交任务的会交给拒绝策略去处理


workQueue


  • 当线程池任务线程数量 < corePoolSize,执行器会创建一个新的线程来执行新添加的任务


  • 当线程池任务线程数量 > corePoolSize,且workQueue未满时,执行器将新添加的任务放到workQueue中


  • 当线程池任务线程数量 > corePoolSize,且workQueue已满时,行器会创建一个新的线程来执行新添加的任务,直到超过maximumPoolSize执行拒绝策略


队列策略


  • Direct handoffs 直接握手队列,使用SynchronousQueue队列,提交的任务会马上执行,不会被保存,如果执行任务线程数小于maximumPoolSize,则尝试创建新的进程,如果达到maximumPoolSize,则执行拒绝策略


  • Bounded queues 有界队列,一般使用ArrayBlockingQueue制定队列的最大长度,当创建线程数达到corePoolSize时,若有新任务加入,则直接进入任务队列等待,若等待队列已满,即超过ArrayBlockingQueue初始化的容量,则继续创建线程,直到线程数达到maximumPoolSize,则执行拒绝策略


  • Unbounded queues 无界队列,一般使用无预定长度的LinkedBlockingQueue,当线程数达到corePoolSize后,若有新任务加入,则直接进入任务队列等待,任务队列可以无限添加新的任务,maximumPoolSize参数是无效的


RejectedExecutionHandler


  • 当线程池已经被关闭,或者任务数超过maximumPoolSize+workQueue时执行拒绝策略


  • ThreadPoolExecutor.AbortPolicy 默认拒绝策略,丢弃任务并抛出RejectedExecutionException异常


  • ThreadPoolExecutor.DiscardPolicy 直接丢弃任务,但不抛出异常


  • ThreadPoolExecutor.DiscardOldestPolicy 丢弃任务队列最先加入的任务,再执行execute方法把新任务加入队列执行


  • ThreadPoolExecutor.CallerRunsPolicy 会调用当前线程池的所在的线程去执行被拒绝的任务


线程池任务的执行流程



三、实现


1.SynchronousQueue


创建 ThreadPoolExecutorTest类,默认使用ThreadPoolExecutor.AbortPolicy拒绝策略,队列是SynchronousQueue,超出核心线程的任务会创建新的线程来执行,设置核心线程数最大值为4,线程池线程数最大值为8,最大等待时间为5秒


public class ThreadPoolExecutorTest {
    public static void main(String[] args) throws InterruptedException {
        // 1.创建自定义线程池
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(4, 8, 5, 
        TimeUnit.SECONDS, 
        new SynchronousQueue<>(),
        Executors.defaultThreadFactory(),
        new ThreadPoolExecutor.AbortPolicy());
        // 2.创建线程任务
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                    System.out.println(Thread.currentThread().getName() + " run");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        // 3.执行任务
        System.out.println("设置核心线程数最大值为4,线程池线程数最大值为8");
        System.out.println("&&&&开始执行线程&&&&");
        System.out.println("----执行4个任务----");
        threadPoolExecutor.execute(runnable);
        threadPoolExecutor.execute(runnable);
        threadPoolExecutor.execute(runnable);
        threadPoolExecutor.execute(runnable);
        System.out.println("当前核心线程数" + threadPoolExecutor.getCorePoolSize());
        System.out.println("当前线程池线程数" + threadPoolExecutor.getPoolSize());
        System.out.println("当前队列任务数" + threadPoolExecutor.getQueue().size());
        System.out.println("----再执行4个任务----");
        threadPoolExecutor.execute(runnable);
        threadPoolExecutor.execute(runnable);
        threadPoolExecutor.execute(runnable);
        threadPoolExecutor.execute(runnable);
        System.out.println("当前核心线程数" + threadPoolExecutor.getCorePoolSize());
        System.out.println("当前线程池线程数" + threadPoolExecutor.getPoolSize());
        System.out.println("当前队列任务数" + threadPoolExecutor.getQueue().size());
        Thread.sleep(10000);
        System.out.println("----休眠10秒后----");
        System.out.println("当前核心线程数" + threadPoolExecutor.getCorePoolSize());
        System.out.println("当前线程池线程数" + threadPoolExecutor.getPoolSize());
        System.out.println("当前队列任务数" + threadPoolExecutor.getQueue().size());
        // 4.关闭线程池
        threadPoolExecutor.shutdown();
    }
}


一共有4个核心,超过核心线程将创建非核心线程,核心线程默认情况下不会被回收,不受时间限制,而超时的非核心线程将被回收



但如果再执行4个任务,线程数超过maximumPoolSize,再提交任务将被丢弃并抛出RejectedExecutionException异常



2.ArrayBlockingQueue


当线程数达到corePoolSize后,若有新任务加入,则直接进入任务队列等待,超出队列的任务会创建新的线程来执行


        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(4, 8, 5, 
        TimeUnit.SECONDS, 
        new ArrayBlockingQueue<>(4),
        Executors.defaultThreadFactory(),
        new ThreadPoolExecutor.AbortPolicy());


一共有4个核心,当线程数超过corePoolSize+workQueue时,将创建非核心线程,核心线程默认情况下不会被回收,不受时间限制,而超时的非核心线程将被回收



但如果再执行4个任务,线程数超过maximumPoolSize+workQueue,再提交任务将被丢弃并抛出RejectedExecutionException异常



3.LinkedBlockingQueue


当线程数达到corePoolSize后,若有新任务加入,则直接进入任务队列等待,任务队列可以无限添加新的任务,maximumPoolSize参数是无效的


        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(4, 8, 5, 
        TimeUnit.SECONDS, 
        new LinkedBlockingDeque<>(), 
        Executors.defaultThreadFactory(),
        new ThreadPoolExecutor.AbortPolicy());    


一共有4个核心,超过核心线程将创建非核心线程,核心线程默认情况下不会被回收,不受时间限制,而超时的非核心线程将被回收



但当设置LinkedBlockingDeque容量限制为4时,当线程数超过corePoolSize+workQueue时,将创建非核心线程,核心线程默认情况下不会被回收,不受时间限制,而超时的非核心线程将被回收


        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(4, 8, 5, 
        TimeUnit.SECONDS, 
        new LinkedBlockingDeque<>(4), 
        Executors.defaultThreadFactory(),
        new ThreadPoolExecutor.AbortPolicy());



但如果再执行4个任务,线程数超过maximumPoolSize+workQueue,再提交任务将被丢弃并抛出RejectedExecutionException异常



目录
相关文章
|
1天前
|
缓存 Java
【Java基础】简说多线程(上)
【Java基础】简说多线程(上)
5 0
|
2天前
|
并行计算 算法 安全
Java从入门到精通:2.1.3深入学习Java核心技术——掌握Java多线程编程
Java从入门到精通:2.1.3深入学习Java核心技术——掌握Java多线程编程
|
2天前
|
安全 Java 编译器
是时候来唠一唠synchronized关键字了,Java多线程的必问考点!
本文简要介绍了Java中的`synchronized`关键字,它是用于保证多线程环境下的同步,解决原子性、可见性和顺序性问题。从JDK1.6开始,synchronized进行了优化,性能得到提升,现在仍可在项目中使用。synchronized有三种用法:修饰实例方法、静态方法和代码块。文章还讨论了synchronized修饰代码块的锁对象、静态与非静态方法调用的互斥性,以及构造方法不能被同步修饰。此外,通过反汇编展示了`synchronized`在方法和代码块上的底层实现,涉及ObjectMonitor和monitorenter/monitorexit指令。
12 0
|
2天前
|
监控 安全 Java
在Java中如何优雅的停止一个线程?可别再用Thread.stop()了!
在Java中如何优雅的停止一个线程?可别再用Thread.stop()了!
9 2
|
2天前
|
Java 调度
Java面试必考题之线程的生命周期,结合源码,透彻讲解!
Java面试必考题之线程的生命周期,结合源码,透彻讲解!
24 1
|
16天前
|
存储 Java 数据库连接
java多线程之线程通信
java多线程之线程通信
|
27天前
|
存储 缓存 NoSQL
Redis单线程已经很快了6.0引入多线程
Redis单线程已经很快了6.0引入多线程
31 3
|
30天前
|
消息中间件 安全 Linux
线程同步与IPC:单进程多线程环境下的选择与权衡
线程同步与IPC:单进程多线程环境下的选择与权衡
58 0
|
1月前
|
Java 调度 C#
C#学习系列相关之多线程(一)----常用多线程方法总结
C#学习系列相关之多线程(一)----常用多线程方法总结
|
1月前
|
安全 编译器 C#
C#学习相关系列之多线程---lock线程锁的用法
C#学习相关系列之多线程---lock线程锁的用法

热门文章

最新文章