你对Java线程池理解吗?你有用过线程池吗?那先说下线程池外围参数吧。。。对不起,我回去再看看吧。

为了一丝体面,咱们明天来整顿几个面试中常考线程池面试问题吧!

为什么要用线程池?


  1. 线程复用。线程的重复使用是线程池设计的重点,如果须要开启1000个线程执行程序,零碎会创立1000个线程,如果用线程池来执行1000个工作,并不需要开启1000个线程,只须要设置corePoolSize外围线程大小数量,最大线程数量,队列大小即可反复利用线程置换工作,而且1000个线程切换效率并不低,也就是说线程越多效率不肯定高。所以在多线程环境理论开发中咱们举荐用多线程。
  2. 更好的治理线程。ThreadPoolExecutor能够控制线程数量,依据理论利用场景设置队列数量和饱和策略。

你说下线程池外围参数?


  • corePoolSize : 外围线程大小。线程池始终运行,外围线程就不会进行。
  • maximumPoolSize :线程池最大线程数量。非核心线程数量=maximumPoolSize-corePoolSize
  • keepAliveTime :非核心线程的心跳工夫。如果非核心线程在keepAliveTime内没有运行工作,非核心线程会沦亡。
  • workQueue :阻塞队列。ArrayBlockingQueue,LinkedBlockingQueue等,用来寄存线程工作。
  • defaultHandler :饱和策略。
  • ThreadFactory :线程工厂。新建线程工厂。

execute工作增加流程?


  1. 线程池执行execute/submit办法向线程池增加工作,当工作小于外围线程数corePoolSize,线程池中能够创立新的线程。
  2. 当工作大于外围线程数corePoolSize,就向阻塞队列增加工作。
  3. 如果阻塞队列已满,须要通过比拟参数maximumPoolSize,在线程池创立新的线程,当线程数量大于maximumPoolSize,阐明以后设置线程池中线程曾经解决不了了,就会执行饱和策略。

饱和策略晓得吗?


上图咱们说过,当线程数量大于maximumPoolSize,就会执行饱和策略。ThreadPoolExecutor类中一共有4种饱和策略。通过实现RejectedExecutionHandler接口。

  • AbortPolicy : 线程工作抛弃报错。默认饱和策略。
  • DiscardPolicy : 线程工作间接抛弃不报错。
  • DiscardOldestPolicy : 将workQueue队首工作抛弃,将最新线程工作重新加入队列执行。
  • CallerRunsPolicy :线程池之外的线程间接调用run办法执行。

上面咱们在代码中看下饱和策略应用形式。

import java.util.concurrent.ArrayBlockingQueue;import java.util.concurrent.CountDownLatch;import java.util.concurrent.ThreadPoolExecutor;import java.util.concurrent.TimeUnit;import java.util.concurrent.atomic.AtomicInteger;/** * @author :jiaolian * @date :Created in 2021-02-20 16:28 * @description:线程池抛弃策略 * @modified By: * 公众号:叫练 */public class AbortTest {    //线程数量 private static final int THREAD_COUNT = 50;    private static final CountDownLatch COUNT_DOWN_LATCH = new CountDownLatch(THREAD_COUNT);    private static final AtomicInteger ATOMIC_INTEGER = new AtomicInteger(1);    //线程池抛弃策略 public static void main(String[] args) throws InterruptedException {        //新建一个线程池 ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(                3,5,1, TimeUnit.SECONDS,                new ArrayBlockingQueue<Runnable>(20),new ThreadPoolExecutor.AbortPolicy());        //DiscardPolicy 抛弃 //AbortPolicy 抛弃报错 //DiscardOldestPolicy 将队列对首的工作抛弃,执行以后线程工作 //CallerRunsPolicy 间接调用run办法 //提交线程 for (int i=0; i<THREAD_COUNT; i++) {            threadPoolExecutor.execute(()->{                try {                    Thread.sleep(2000);                } catch (InterruptedException e) {                    e.printStackTrace();                }                System.out.println(Thread.currentThread().getName()+" execute!"+ATOMIC_INTEGER.getAndIncrement());                COUNT_DOWN_LATCH.countDown();            });        }        COUNT_DOWN_LATCH.await();        //敞开线程 threadPoolExecutor.shutdown();    }}

如上代码:外围线程数量是3,最大线程数量是5,阻塞队列是20,共提交50个线程,这里饱和策略用的是AbortPolicy,剖析执行线程池过程,线程池中首先开启3个外围线程Worker,发现3个线程解决不了50个线程工作,于是线程池就向阻塞队列增加工作,发现还是阻塞队列也包容不下50个工作,于是又减少至2个线程同时运行线程工作,一共是5个线程同时运行工作,此时线程池中共有25个工作会被执行,还有25个工作会被抛弃,因为咱们用的是AbortPolicy饱和策略,会报错,截局部图如下划红线所示。一共执行了25个工作。其余几种策略大家能够参照执行。

你平时线程池怎么用的?


  • Excutors.newSingleThreadExecutor :1个corePoolSize,LinkedBlockingQueue队列无限大,当创立无数个线程,队列有限长,可能呈现OOM内存溢出。繁多线程。
  • Executors.newCachedThreadPool :0个corePoolSize,Interger.MAX_VALUE最大线程数,当创立无数个线程,可能呈现OOM内存溢出。实用小而多线程。
  • Executors.newFixedThreadPool :n个corePoolSize,n个最大线程个数,LinkedBlockingQueue阻塞队列,当创立无数个线程,队列有限长,可能呈现OOM内存溢出。实用固定线程。
  • Executors.newScheduledThreadPool :n个corePoolSize,Interger.MAX_VALUE个最大线程数,当创立无数个线程,可能呈现OOM内存溢出。

源码中线程池是怎么复用线程的?


源码中ThreadPoolExecutor中有个内置对象Worker,每个worker都是一个线程,worker线程数量和参数无关,每个worker会while死循环从阻塞队列中取数据,通过置换worker中Runnable对象,运行其run办法起到线程置换的成果,这样做的益处是防止多线程频繁线程切换,进步程序运行性能。

总结


明天咱们介绍了线程池中面试中几个重要的面试点,整理出来心愿能对你有帮忙,写的比不全,同时还有许多须要修改的中央,心愿亲们加以斧正和点评,喜爱的请点赞加关注哦。点关注,不迷路,我是叫练【公众号】,微信号【jiaolian123abc】边叫边练。