• java线程池


    转自:https://www.jianshu.com/p/9beab78a3afe

    接下来三篇文章主要围绕Java线程池的三个方面进行编写

    第一个方面Exectutor,该类是Java线程池的顶层抽象类

    第二个方面:讲述Java线程池中的各种线程池

    第三个方面:讲述Future和FutureTask,线程的返回结果处理类

    ThreadPoolExecutor通常使用工厂类Executors来创建。Executors可以创建3种类型的ThreadPoolExecutor:SingleThreadPool、FixedThreadPool和CachedThreadPool。

    ScheduledThreadPoolExecutor通常使用工厂类Executors来创建。Executors可以创建2种类型的ScheduledThreadPoolExecutor:SingleScheduledThreadPoo和ScheduledThreadPool

    注意:使用Executors来创建线程池,失去了线程池的灵活性,而且存在一定的隐患,根据阿里巴巴规范插件的提示,使用Executors来创建线程池存在资源耗尽的可能,因为使用Executors来创建线程池默认的最大容量是Integer.Max,也就是Integer的最大值作为线程池的最大容量,这样在程序中可能出现错误,导致创建了Integer.Max个线程,存在内存溢出的风险。所以在熟练掌握线程池原理后可以使用ThreadPoolExecutor根据添加不同的参数创建不同类型的线程池。

    ThreadPoolExecutor

    了解ThreadPoolExecutor可以查看《Java线程池原理》

    public ThreadPoolExecutor(int corePoolSize, 

                                                int maximumPoolSize,

                                                long keepAliveTime,

                                                 TimeUnit unit,

                                                 BlockingQueue workQueue,

                                                 ThreadFactory threadFactory,

                                                 RejectedExecutionHandler handler) 

    下面解释构造函数的参数含义

    corePoolSize:核心线程数量

    maximumPoolSize:最大线程数量;

    workQueue:等待队列,当任务提交时,如果线程池中的线程数量大于等于corePoolSize的时候,把该任务封装成一个Worker对象放入等待队列;

    keepAliveTime:线程池维护线程所允许的空闲时间。当线程池中的线程数量大于corePoolSize的时候,如果这时没有新的任务提交,核心线程外的线程不会立即销毁,而是会等待,直到等待的时间超过了keepAliveTime;

    TimeUnit :时间级别

    threadFactory:它是ThreadFactory类型的变量,用来创建新线程。

    handler:它是RejectedExecutionHandler类型的变量,表示线程池的饱和策略。如果阻塞队列满了并且没有空闲的线程,这时如果继续提交任务,就需要采取一种策略处理该任务。

    ThreadFactory:定义线程池中创建的线程,如线程名称,优先级等,可以几次ThreadFactory重新newThread(Runnable r)方法。

     
    CustomThreadFactory

    Executors

    虽然使用Executors创建线程池存在一定的风险,但是在有些不是很复杂的场景,合理使用Executors还是可行的。下面使用Executors来创建不同类型的线程池

    固定数量线程池(newFixedThreadPool)

    创建使用固定线程数的FixedThreadPool,适用于为了满足资源管理的需求,而需要限制当前线程数量的应用场景,它适用于负载比较重的服务器。

    Executors构造newFixedThreadPool方式

     

    查看源码

     

    corePoolSize = maximumPoolSize =初始化的参数

    workQueue:使用无界队列LinkedBlockingQueue链表阻塞队列

    keepAliveTime = 0 由于使用无界队列LinkedBlockingQueue作为缓存队列,所以当corePoolSize满后,后面添加的线程任务都会添加到LinkedBlockingQueue中去,所以maximumPoolSize 就失去了意义,这样也就没有必要设置空闲时间

    使用无界队列的影响,这也是为什么使用Eexcutors来创建线程池存在一定风险的原因

    1)当线程池中的线程数达到corePoolSize后,新任务将在无界队列中等待,因此线程池中的线程数不会超过corePoolSize。

    2)使用无界队列时maximumPoolSize将是一个无效参数。

    3)使用无界队列时keepAliveTime将是一个无效参数。

    4)由于使用无界队列,运行中的FixedThreadPool(未执行方法shutdown()或shutdownNow())不会拒绝任务(不会调用RejectedExecutionHandler.rejectedExecution方法)。

    代码实例

     

    结果:

     

    为什么线程名称会重复:这正是线程池的原理,因为线程池会重复利用已创建的线程,当一个任务Runnable被挂载到线程池中的一个线程,这个任务执行完毕后,会有另一个任务继续挂载到这个线程上面,所以会出现线程名称重复。

    单例线程池(newSingleThreadExecutor)

    适用于需要保证顺序地执行各个任务;并且在任意时间点,不会有多个线程是活动的应用场景。

    Executors构造newSingleThreadExecutor方式

     

    源代码

     

    corePoolSize = maximumPoolSize =1  由于是单例线程池,所以线程池中是有一个重用的线程

    workQueue:使用无界队列LinkedBlockingQueue链表阻塞队列

    keepAliveTime:0 原因上面已经阐述

    代码实例

     

    结果

     

    只有一个可重用的线程,任务的执行顺序和添加顺序一致

    缓存线程池(newCachedThreadPool)

    创建一个会根据需要创建新线程的,适用于执行很多的短期异步任务的小程序,或者是负载较轻的服务器。

    Executors构造newCachedThreadPool方式

     

    源代码

     

    corePoolSize:0 表示线程池中没有核心线程,都是非核心线程

    maximumPoolSize :线程池容量Integer最大值

    keepAliveTime:60秒 由于没有核心线程的存在,线程池中创建的线程都是非核心线程,所以设置空闲时间60秒,当非核心线程60秒后没有被重用,将会被销毁,如果没有线程提交给该线程池,超过空闲时间,该线程池就没有非空闲线程,那么该线程池也就不会消耗过多的资源,

    workQueue:SynchronousQueue是一个不存储元素的阻塞队列。每一个put操作必须等待一个take操作,否则不能继续添加元素。

    代码实例

     

    结果

     

    定时线程池(newScheduledThreadPool)

    它主要用来在给定的延迟之后运行任务,或者定期执行任务,例如定时轮询数据库中的表的数据

    Executors构造newScheduledThreadPool方式

     

    源代码

     

    workQeueu:delayWorkQueue,使用延迟队列作为缓存队列

    任务提交方式

     

    schedule(Callable<E> callable, long delay, TimeUnit unit);

    callable:提交Callable或者Runnable任务

    delay:延迟时间

    unit:时间级别

    该方法表示在给定的delay延迟时间后执行一次,有返回结果

    scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit);

    command:提交Runnable任务

    initialDelay:初始延迟时间

    period:表示连个任务连续执行的时间周期,第一个任务开始到第二个任务的开始,包含了任务的执行时间

    unit:时间级别

    该方法在initialDelay时间后开始周期性的按period时间间隔执行任务

    scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit);

    command:提交Runnable任务

    initialDelay:初始延迟时间

    delay:表示延迟时间 第一个任务结束到第二个任务开始的时间间隔

    unit:时间级别

    代码实例

     

    结果

     

    单例延迟线程池(newSingleThreadScheduledExecutor)

    Executors构造newSingleThreadScheduledExecutor方式

     

    源代码

     

    corePoolSize :1由于是单例线程池,所以核心线程为1,线程池中只有一个重用线程

  • 相关阅读:
    Java(14):面向对象、封装、继承、方法重写、多态、抽象类与接口、内部类
    Java(13):数组、Arrays类、冒泡排序
    Java(12):方法、重载、命令行传参、可变参数、方法调用
    Java(11):switch、dowhile、九九乘法表、打印质数、打印三角形
    Java(10):用户交互Scanner
    Java(9):包
    Java(8):运算符
    Java(7):变量和常量及其规范、作用域
    Mybatis 打印日志
    mysql 更新数据
  • 原文地址:https://www.cnblogs.com/wjqhuaxia/p/11747868.html
Copyright © 2020-2023  润新知