面试官司连续“炮轰”线程池问题,能否接住?

线程池在JAVA知识中,占有相当重要的地位!下面看看面试官都会问线程池哪些方面的知识点,来考查我们对线程池基本知识撑握情况、及使用熟练度!

开始

面试官:用过JAVA中的线程池嘛?是怎么用的?能大概说下使用方法嘛?

我:在java.util.concurrent包下有个 ThreadPoolExecutor 工具类,可以用它创建一个普通的线程池。使用方法是:

    @Bean    public ExecutorService executorService() {        return new ThreadPoolExecutor(                5,                150,                1500,                TimeUnit.SECONDS,                new LinkedBlockingQueue<>(),                new WorkThreadFactory("EXE")        );    }

如果要创建定时任务线程池,java.util.concurrent包下的 Executors 工具包创建。使用方法是,调用其中的方法:

    @Bean    public ScheduledExecutorService scheduledExecutorService() {        return Executors.newScheduledThreadPool(                20,                new WorkThreadFactory("SCH")        );    }

面试官在问这个问题除了考查我们会不会用外,也在考查我们会不会去查看JDK下包的源码,会不会深入研究。

面试官:能详细讲下线程池的状态吗?

我:在 ThreadPoolExecutor 类中,定义了 线程池5各状态:

  • RUNNING  线程池可以接收新的任务和执行已添加的任务

  • SHUTDOWN   线程池处在SHUTDOWN状态时,不接收新任务,但能处理已添加的任务

  • STOP  不接收新任务,不处理已添加的任务,并且会中断正在执行的任务

  • TIDYING   当所有的任务已终止,记录的”任务数量”为0,线程池会变为TIDYING状态。当线程池变为TIDYING状态时,会执行钩子函数terminated()

  • TERMINATED  当钩子函数terminated()被执行完成之后,线程池彻底终止,就变成TERMINATED状态

线程池中状态之间的转换:

当线程池被创建成功后,就处于 RUNNING  状态,这个时候线程池中的任务数为0,能够接收新任务,对已添加的任务进行处理。

当一个线程池调用 shutdown() 方法后,线程池从RUNNING  ->  SHUTDOWN

当调用线程池的shutdownNow()方法后,线程池由(RUNNING或者SHUTDOWN ) -> STOP

当线程池在SHUTDOWN状态下,阻塞队列为空并且线程池中执行的任务也为空时,就会由 SHUTDOWN -> TIDYING。当线程池在STOP状态下,线程池中执行的任务为空时,会由STOP -> TIDYING

线程池处在TIDYING状态时,执行完terminated()之后,就会由 TIDYING -> TERMINATED

面试官:常用的有哪几种线程池?

我:常用的有4种线程池

  • newFixedThreadPool

public static ExecutorService newFixedThreadPool(int nThreads) {        return new ThreadPoolExecutor(nThreads, nThreads,                                      0L, TimeUnit.MILLISECONDS,                                      new LinkedBlockingQueue<Runnable>());}

创建一个固定大小的线程池,每次提交一个任务就创建一个线程,直到线程达到线程池的最大值nThreads。线程池的大小一旦达到最大值后,再有新的任务提交时则放入无界阻塞队列中,等到有线程空闲时,再从队列中取出任务继续执行

  • newCachedThreadPool

  • public static ExecutorService newCachedThreadPool() {        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,                                      60L, TimeUnit.SECONDS,                                      new SynchronousQueue<Runnable>());    }

    创建了一个可缓存的线程池。当有新的任务提交时,有空闲线程则直接处理任务,没有空闲线程则创建新的线程处理任务,队列中不储存任务。线程池不对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。如果线程空闲时间超过了60秒就会被回收

  • newSingleThreadExecutor

    创建了一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序执行

  • public static ExecutorService newSingleThreadExecutor() {        return new FinalizableDelegatedExecutorService            (new ThreadPoolExecutor(1, 1,                                    0L, TimeUnit.MILLISECONDS,                                    new LinkedBlockingQueue<Runnable>()));}
    
  • newScheduledThreadPool

    创建了一个固定大小的线程池,支持定时及周期性任务执行

  •     public ScheduledThreadPoolExecutor(int corePoolSize,                                       ThreadFactory threadFactory) {        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,              new DelayedWorkQueue(), threadFactory);    }
    

以上为四种常见的线程池,在理解线程池的时候,里面的参数也很重要。下面为最后调用的方法。其中有7个参数。

    public ThreadPoolExecutor(int corePoolSize,                              int maximumPoolSize,                              long keepAliveTime,                              TimeUnit unit,                              BlockingQueue<Runnable> workQueue,                              ThreadFactory threadFactory,                              RejectedExecutionHandler handler) {        if (corePoolSize < 0 ||            maximumPoolSize <= 0 ||            maximumPoolSize < corePoolSize ||            keepAliveTime < 0)            throw new IllegalArgumentException();        if (workQueue == null || threadFactory == null || handler == null)            throw new NullPointerException();        this.acc = System.getSecurityManager() == null ?                null :                AccessController.getContext();        this.corePoolSize = corePoolSize;        this.maximumPoolSize = maximumPoolSize;        this.workQueue = workQueue;        this.keepAliveTime = unit.toNanos(keepAliveTime);        this.threadFactory = threadFactory;        this.handler = handler;    }


corePoolSize : 为核心线程数量

maximumPoolSize: 线程池允许最大线程数

keepAliveTime : 表示能够呆多长时间,参数为数字

TimeUnit :为呆的时间单位。 秒;分

BlockingQueue : 为达到了核心线程池后,把任务添加到队列中

ThreadFactory :为线程工厂,就是用来创建线程

RjectedExecutionHandler : 为拒绝策略,在达到了最大线程数,同时队列也最大了

BlockingQueue 本身是一个接口,其功能可以使用默认的,也可以使用自已写的。可以 链表、数组等数组结构存储

RjectedExecutionHandler  拒绝策略有4种:

  1. 直接抛异常   能够知道线程已经超过最大限制了   

  2. 直接丢弃,没提示  直接把任务丢掉

  3. 加入队列,替换队列中停留时间最长的

  4. 由提交线程处理

以上的4种策略,前3种会有数据丢失的现象。

面试官问这些问题,不论是参数、线程队列,还是拒绝策略,是对我们对线程池的知识进行了一个全面、低层的盘问​。​

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

周周的JAVA技术栈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值