zoukankan      html  css  js  c++  java
  • Java线程池

    Java的线程池,各个参数的作用,如何进行的?

    1.线程池核心参数

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

    线程池可以通过ThreadPoolExecutor来创建,我们来看一下它的几个核心参数:

    • corePoolSize: 线程池核心线程数最大值
    • maximumPoolSize: 线程池最大线程数大小
    • keepAliveTime: 线程池中非核心线程空闲的存活时间大小
    • unit: 线程空闲存活时间单位
    • workQueue: 存放任务的阻塞队列
    • threadFactory: 用于设置创建线程的工厂,可以给创建的线程设置有意义的名字,可方便排查问题。
    • handler: 线城池的饱和策略事件,主要有四种类型。

    核心线程和非核心线程区别:

    核心线程: 可闲置 不会被销毁  。(ThreadPoolExecutor的allowCoreThreadTimeOut属性设置为true时,keepAliveTime同样会作用于核心线程)

    非核心线程:非核心线程当闲置时间超过 keepAliveTime这个时长,非核心线程就会被回收。

    核心线程数就像是工厂正式工,最大线程数,就是工厂临时工作量加大,请了一批临时工,临时工加正式工的和就是最大线程数,等这批任务结束后,临时工要辞退的,而正式工留下。

    2.线程池创建流程

    • 提交一个任务,如果当前工作中的线程数量少于corePoolSize,就创建新的线程来执行任务。
    • 当线程池的工作中的线程数量达到了corePoolSize,新提交的任务,会被放进任务队列workQueue排队等待执行。
    • 当线程池里面存活的线程数达到corePoolSize了,并且任务队列workQueue也满,判断线程数是否达到maximumPoolSize,即最大线程数是否已满,如果没到达,创建一个非核心线程执行提交的任务。
    • 如果当前的线程数达到了maximumPoolSize,还有新的任务过来的话,直接采用拒绝策略处理。

      

    3.四种拒绝策略

    • AbortPolicy(抛出一个异常,默认的)
    • DiscardPolicy(直接丢弃任务)
    • DiscardOldestPolicy(丢弃队列里最老的任务,将当前这个任务继续提交给线程池)
    • CallerRunsPolicy(交给线程池调用所在的线程进行处理)

    4. 线程池的作用:

    池化技术应用:线程池、数据库连接池、http连接池等等。

    池化技术的思想主要是为了减少每次获取资源的消耗,提高对资源的利用率。

    使用线程池的好处:

    • 降低资源消耗:通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

    • 提高响应速度:当任务到达时,可以不需要等待线程创建就能立即执行。

    • 提高线程的可管理性:线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,监控和调优。

    5.线程池中线程的生命周期

    设:我们有一个coreSize=10,maxSize=20,keepAliveTime=60s,queue=40
    1、池初始化时里面没有任何线程。
    2、当有一个任务提交到池就创建第一个线程。
    3、若继续提交任务,有空闲线程就调拨空闲线程来处理任务?若没有线程空闲则再新建一个线程来处理,如此直到coreSize。【预热阶段
    4、若继续提交任务,有空闲线程就调拨空闲线程来处理任务,如果没有空闲线程(10个)则将任务缓存到queue中排队等待。
    5、若继续提交任务,而已有线程不空闲,且queue也满了,则新建线程,并将最新的任务优先提交给新线程处理。
    6、若继续提交任务,且所有线程(20个)仍不空闲,queue也是满的,此时就会触发池的拒绝机制。
    8、一旦有任何线程空闲下来就会从queue中消费任务,直到queue中任务被消费完。
    9、当总忙碌线程个数不超过coreSize时,闲暇线程休息keepAliveTime过后会被销毁。
    10、而池中一直保留coreSize个线程存活。

    6.线程池的实现原理

    其实java线程池的实现原理很简单,说白了就是一个线程集合workerSet和一个阻塞队列workQueue。当用户向线程池提交一个任务(也就是线程)时,线程池会先将任务放入workQueue中。workerSet中的线程会不断的从workQueue中获取线程然后执行。当workQueue中没有任务的时候,worker就会阻塞,直到队列中有任务了就取出来继续执行

    线程池都有哪几种工作队列?

    1.线程池的5种工作队列

    • ArrayBlockingQueue
    • LinkedBlockingQueue
    • DelayQueue
    • PriorityBlockingQueue
    • SynchronousQueue

    任务太多的时候,工作队列用于暂时缓存待处理的任务,jdk中常见的5种阻塞队列:

    ArrayBlockingQueue(数组阻塞队列):是一个基于数组结构的有界阻塞队列,此队列按照先进先出原则对元素进行排序

    LinkedBlockingQueue(链表阻塞队列):是一个基于链表结构的阻塞队列,此队列按照先进先出排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool使用了这个队列。

    DelayQueue(延迟队列):是一个任务定时周期的延迟执行的队列。根据指定的执行时间从小到大排序,否则根据插入到队列的先后排序。newScheduledThreadPool线程池使用了这个队列。

    PriorityBlockingQueue(优先级阻塞队列):优先级队列,进入队列的元素按照优先级会进行排序。

    SynchronousQueue (同步队列):一个不存储元素的阻塞队列,每个插入操作必须等到另外一个线程调用移除操作,否则插入操作一直处理阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用这个队列。

    几种常见的线程池及使用场景

    1. 四种常用的线程池

    • newFixedThreadPool (固定数目线程的线程池)
    • newCachedThreadPool(可缓存线程的线程池)
    • newSingleThreadExecutor(单线程的线程池)
    • newScheduledThreadPool(定时及周期执行的线程池)

    a.newFixedThreadPool:

    • 通俗:创建可容纳固定数量线程的池子,每个线程的存活时间是无限的,当池子满了就不在添加线程了;如果池中的所有线程均在繁忙状态,对于新任务会进入阻塞队列中(无界的阻塞队列)
    • 适用:FixedThreadPool 适用于处理CPU密集型的任务,确保CPU在长期被工作线程使用的情况下,尽可能的少的分配线程,即适用执行长期的任务。
    • 特点:
      • 核心线程数和最大线程数大小一样
      • 没有所谓的非核心线程空闲时间,即keepAliveTime为0
      • 阻塞队列为无界队列LinkedBlockingQueue

      问:使用无界队列的线程池会导致内存飙升吗?

      答:会的,newFixedThreadPool使用了无界的阻塞队列LinkedBlockingQueue,如果线程获取一个任务后,任务的执行时间比较长(比如,上面demo设置了10秒),会导致队列的任务越积越多,导致机器内存使用不停飙升, 最终导致OOM。

    b.newCachedThreadPool:

    • 通俗:当有新任务到来,则插入到SynchronousQueue中,由于SynchronousQueue是同步队列,因此会在池中寻找可用线程来执行,若有可以线程则执行,若没有可用线程则创建一个线程来执行该任务;若池中线程空闲时间超过指定大小,则该线程会被销毁。
    • 适用:执行很多短期异步的小程序或者负载较轻的服务器.(用于并发执行大量短期的小任务。)
    • 特点:
      • 核心线程数为0
      • 最大线程数为Integer.MAX_VALUE
      • 阻塞队列是SynchronousQueue
      • 非核心线程空闲存活时间为60秒

    c.newSingleThreadExecutor:

    • 通俗:创建只有一个线程的线程池,且线程的存活时间是无限的;当该线程正繁忙时,对于新任务会进入阻塞队列中(无界的阻塞队列)
    • 适用:适用于串行执行任务的场景,一个任务一个任务地执行。
    • 特点:
      • 核心线程数为1
      • 最大线程数也为1
      • 阻塞队列是LinkedBlockingQueue
      • keepAliveTime为0

    d.newScheduledThreadPool:

    • 通俗:创建一个固定大小的线程池,线程池内线程存活时间无限制,线程池可以支持定时及周期性任务执行,如果所有线程均处于繁忙状态,对于新任务会进入DelayedWorkQueue队列中,这是一种按照超时时间排序的队列结构
    • 适用:周期性执行任务的场景,需要限制线程数量的场景
    • 特点:
        • 最大线程数为Integer.MAX_VALUE
        • 阻塞队列是DelayedWorkQueue
        • keepAliveTime为0
        • scheduleAtFixedRate() :按某种速率周期执行
        • scheduleWithFixedDelay():在某个延迟后执行

    2.线程池状态:

    线程池有这几个状态:RUNNING,SHUTDOWN,STOP,TIDYING,TERMINATED。

    RUNNING

    • 该状态的线程池会接收新任务,并处理阻塞队列中的任务;
    • 调用线程池的shutdown()方法,可以切换到SHUTDOWN状态;
    • 调用线程池的shutdownNow()方法,可以切换到STOP状态;

    SHUTDOWN

    • 该状态的线程池不会接收新任务,但会处理阻塞队列中的任务;
    • 队列为空,并且线程池中执行的任务也为空,进入TIDYING状态;

    STOP

    • 该状态的线程不会接收新任务,也不会处理阻塞队列中的任务,而且会中断正在运行的任务;
    • 线程池中执行的任务为空,进入TIDYING状态;

    TIDYING

    • 该状态表明所有的任务已经运行终止,记录的任务数量为0。
    • terminated()执行完毕,进入TERMINATED状态

    TERMINATED

    • 该状态表示线程池彻底终止

    ThreadPoolExecutor的运行状态有5种,分别为:

    其生命周期转换如下入所示:

     

     3.线程池ThreadPoolExecutor中定义的生命周期中的状态及相关方法:

    private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
    private static final int COUNT_BITS = Integer.SIZE - 3; // =29
    private static final int CAPACITY   = (1 << COUNT_BITS) - 1; // =000 11111...
    
    // runState is stored in the high-order bits
    private static final int RUNNING    = -1 << COUNT_BITS; // 111 00000...
    private static final int SHUTDOWN   =  0 << COUNT_BITS; // 000 00000...
    private static final int STOP       =  1 << COUNT_BITS; // 001 00000...
    private static final int TIDYING    =  2 << COUNT_BITS; // 010 00000...
    private static final int TERMINATED =  3 << COUNT_BITS; // 011 00000...
    
    // 线程池的状态
    private static int runStateOf(int c)     { return c & ~CAPACITY; }
    // 线程池中工作线程的数量
    private static int workerCountOf(int c)  { return c & CAPACITY; }
    // 计算ctl的值,等于运行状态“加上”线程数量
    private static int ctlOf(int rs, int wc) { return rs | wc; }
  • 相关阅读:
    Oracle常用命令大全(很有用,做笔记)
    表格驱动编程在代码中的应用
    mac 利用svn下载远程代码出现Agreeing to the Xcode/iOS license requires admin privileges, please re-run as root via sudo.
    FAILURE: Build failed with an exception.
    There is an internal error in the React performance measurement code.Did not expect componentDidMount timer to start while render timer is still in progress for another instance
    react native TypeError network request failed
    Android向系统相册中插入图片,相册中会出现两张 一样的图片(只是图片大小不一致)
    react-native Unrecognized font family ‘Lonicons’;
    react-native SyntaxError xxxxx/xx.js:Unexpected token (23:24)
    Application MyTest has not been registered. This is either due to a require() error during initialization or failure to call AppRegistry.registerComponent.
  • 原文地址:https://www.cnblogs.com/jingpeng77/p/12486872.html
Copyright © 2011-2022 走看看