面试六、多线程之线程池

1、线程池

 

  1.1、executor接口:只有一个execute()方法

  1.2、ExecutorService接口:继承executor,增加了几个重要方法

    1.2.1、shutdown():等待正在执行的线程执行完毕,拒绝接受新线程,关闭线程池

    1.2.2、shutdownNow():立即关闭线程池和当前正在执行的线程,可能会报错。如果需要等待执行中的线程执行完毕,可调用awaitTermination。

    1.2.3、submit():和execute()方法比,多了返回值

  1.3、Executors类:提供了6个创建不同线程池的方法

    1.3.1、newFixedThreadPool():返回ThreadPoolExecutor,固定线程池中的线程数

    1.3.1、newWorkStealingPool():返回ForkJoinPool,

    1.3.1、newSingleThreadPool():返回ThreadPoolExecutor,线程池中只有一个线程,新进入的线程进入排队,保证任务的顺序执行

    1.3.1、newCachedThreadPool():返回ThreadPoolExecutor,线程池中的线程数随着execute()和submit()方法调用自动创建,如果有空余线程则取已有空闲线程不新建

                   每60秒回收空闲线程

    1.3.1、newSingleThreadScheduledExecutor():返回ScheduledThreadPoolExecutor,

    1.3.1、newScheduledThreadPool():返回ScheduledThreadPoolExecutor

  1.4、参数:

    corePoolSize:核心线程数量

    maxmumPoolSize:最大线程数量,核心线程数满时可继续创建线程直到达到最大线程数量

    keepAliveTime:线程的空闲时间,当前线程数量大于核心线程数量时,会将超过空闲时间的线程回收

    threadFactory:线程工厂,用来创建一个新线程时使用的工程,可以设置线程名称,是否daemon线程

    timeunit:空闲时间单位

    workQueue:阻塞队列,有4种

          ArrayBlockingQueue:基于数组的有界队列,有序,新任务进来排到队列最后,因为有界所以可防止资源耗尽的问题

          LinkedBlockingQueue:基于链表的无界队列,当线程数达到corePoolSize后新任务进来会一直存入队列,但不创建线程,即maxmumPoolSize无效

          SynchronousQueue:同步不缓存任务的队列,新任务进来直接调度执行,如线程数不够则创建,如已达到maxmumPoolSize,则执行拒绝策略

          PriorityBlockingQueue:有优先级的无界队列,通过参数comparator来实现

    handler:拒绝策略

          CallerRunsPolicy:直接调用被拒绝任务的run方法,如线程池已经shutdown,则抛弃任务

          AbortPolicy:直接抛弃任务,并抛出RejectedExecutionExcecption

          DiscardPolicy:直接抛弃任务

          DiscardOldestPolicy:尝试抛弃最早放入队列的那个任务,并把当前任务加入队列中

          自定义拒绝策略,实现RejectedExecutionHandler接口

  1.5、线程池运行过程

    1、线程池为空

    2、任务a进入,校验线程数如小于corePoolSize,则创建新线程执行任务

    3、任务a执行完成,线程不会销毁进入阻塞

    4、任务b进入,校验线程数如小于corePoolSize,则继续创建新线程执行任务,一直到线程池中线程数达到corePoolSize

    5、任务c进入,取线程池中的阻塞线程执行任务,如线程池中所有线程都不在阻塞,则将任务加入workQueue,等待线程执行

    6、如果工作队列是无界队列,则可一直将任务塞入队列中等待执行;如工作队列是有界队列,则队列数到限定值后进入队列失败,尝试创建新线程,直到maxmunPoolSize

    7、如果线程池线程数到maxmumPoolSize,工作队列也满了,则会执行reject,默认是AbortPolicy(拒绝任务,并抛出异常)

    8、超出corePoolSize部分到线程,当空闲时间满足后会销毁

  1.6、为什么使用线程池

    可以存放线程,将执行完任务的线程阻塞等待唤醒,避免线程频繁的创建销毁

  1.7、线程调优

    根据需要选择对应的线程:如,需要顺序执行任务则选择SingleThreadExecutor

    设置合适的核心线程数:cpu密集性即cpu使用率较高,则可以将核心线程数设置为n+1;如是io密集型即cpu使用率不高则可讲核心线程数设置为2n

    设置合适的队列大小:如发送短信,任务量大但是处理效率高,此时可通过设置不大的核心线程数和设置较大的队列数;

              如任务数不多但处理效率不高,则可通过设置大的核心线程数和设置较小的队列数,防止线程执行时间过程导致大量任务等待

  1.8、动态调整参数

    setCorePoolSize:覆盖核心线程数

    setMaxmunPoolSize:覆盖最大线程数

    注意:设置时如果corePoolSize>maxmumPoolSize,会出现虽然核心线程数增加了但是活跃线程最大是maxmumPoolSize

        因为在ThreadPoolExecutor.getTask()方法中会对工作线程数和maxmunPoolSize做一次比较,当工作线程数>maxmumPoolSize时返回空即没有获取到task,

        并cas操作工作线程数减一

posted on 2021-08-26 14:54  Iversonstear  阅读(64)  评论(0编辑  收藏  举报

导航