首页 > 编程知识 正文

面试:线程池常见面试问题

时间:2023-05-06 18:22:14 阅读:28286 作者:671

1 .什么是线程池? 好处是什么? cxdxn是由多个线程组成的池,线程池使用池化思想,同样也有连接池、资源池等。

使用线程池具有以下优点:

1.1线程易于统一管理,不会出现“野线程”。 另外,还统一提供了几种管理方法来管理线程的执行状态。 例如,shutdown ) ) 1.2线程作为服务器的稀缺资源,可以通过线程池进行一定的约束,提高线程利用率,避免无限创建线程,避免服务性能损失。 1.3提高服务响应速度,线程随时使用。 用户不需要在意线程的创建和销毁,而是比较这两个进程的消耗性能。 1.4增强线程池,例如ScheduledThreadPoolExecutor,允许任务延期或定期执行。 2 .核心参数? 2.1 int corePoolSize:核心线程数2.2 int maximumPoolSize:最大线程数2.3 long keepAliveTime:生存时间2.4 TimeUnit timeUnit:生存时间单位2.5 blockkkk 工作队列: runnable阻塞队列2.6 threadFactory:线程工厂实例2.7 rejectedexecutionhandler 3360拒绝策略3 .运行进程? 3.1确定线程池的运行状态是否为运行(CTL==0? ) False是否直接返回null 3.2 currentpoolsizecorepoolsize? True —线程池3.3 false-currentworkqueuesizeworkqueuesize? True —将任务放入工作队列3.4 Fasle —是否此时阻塞队列已满并确定currentPoolSize maxPoolSize? True —启动新线程以执行新提交的任务3.5 False —。 拒绝策略4 .是否要执行4.ThreadPoolExecutor的基本实现? 4.1 ThreadPoolExecutor通过一个原子集成器来维持自身的状态。 私有金融工具=newatomicinteger (CTL of )运行,0 ); //privatestaticfinalintrunning=-1 count _ bits; privatestaticfinalintshutdown=0count _ bits; 私有状态inalintstop=1count _ bits; privatestaticfinalinttidying=2count _ bits; privatestaticfinalintterminated=3count _ bits; 4.2内部类workerprivatefinalclassworkerextendsabstractqueuedsynchronizerimplementsrunnable { finalthreadttor },用于保持线程在线程池内部的状态运行第一个任务; 工作器(运行nablefirsttask ) setstate(-1 ); //inhibitinterruptsuntilrunworkerthis.first task=first task; this.thread=getThreadFactory ().newthread ) ) this; (4.2. 1工作器继承了AQS并实现了Runnable,为什么要使用AQS? 使用AQS是为了保证独占性,线程正在运行时加锁保证独占性,空闲时表示该工作器是空闲的,可以执行其他任务。这里使用AQS不使用ReentrantLock 这是因为在不需要可重新输入性的.4.2. 2工作器内部具有Thread对象,Thread通过构造器,ThreadFactory创建的.4.2. 3第一个任务或null 只有在拥有主锁的情况下才能访问。 */privatefinalhashsetworkerworkers=newhashsetworker (; privatebooleanaddworker (runnablefirsttask,boolean core )……}现在查看源代码ThreadPoolExecutor,实际上线程是作为HashSet对象维护的

addWorker ) )方法来添加线程,并在添加线程时获取主锁。

4.4 Worker执行任务的过程 runWorker() 4.4.1 while循环不断地通过getTask()方法获取任务。 4.4.2 getTask()方法从阻塞队列中取任务。 4.4.3 如果线程池正在停止,那么要保证当前线程是中断状态,否则要保证当前线程不是中断状态。 4.4.4 执行任务。 4.4.5 如果getTask结果为null则跳出循环,执行processWorkerExit()方法,销毁线程。 5.Executors中提供了几种现成的线程池? 阿里规约中为什么不推荐使用? 四种,都是基于ThreadPoolExecutor实现; 5.1 FixedThreadPool public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());} 5.2 SingleThreadPool public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));} 5.3 ScheduledThreadPool public static ScheduledExecutorService newSingleThreadScheduledExecutor() { return new DelegatedScheduledExecutorService (new ScheduledThreadPoolExecutor(1));}public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue());} 5.4 CacheThreadPool public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());}

可以看到FixedThreadPool和SingleThreadPool都是使用了LinkedBlockingQueue,这个阻塞队列最大长度是Integer最大值
而ScheduledThreadPool和CacheThreadPool最大线程数Integer.MAX_VALUE

6.有几种BlockQueue? 延时队列如何实现的? 这里的BlockQueue是线程池的任务缓冲部分,当线程都在运行时Task进入BlockQueue中.

7.拒绝策略? 7.1 丢弃当前任务,并跑出异常.适合重要的逻辑中,抛出异常,方便开发,迅速感知定位问题.7.2 丢弃当前任务,不抛异常,适合非重要的任务.7.3 丢弃最老的任务,重新将新任务添加入队列,这个需要根据自己的需求来定.7.4 由调度线程完成执行当前任务.这个情况下需要其他的任务都执行完成. 8.现实开发中,如何设置线程池的大小?

前面说了这么多,毕竟线程池是我们实际开发中的一个工具.我们还是要在实际的开发中使用.在实际的开发中国,根据不同的需求,场景,如何设置线程池的大小呢??

我们一般说业务分为:IO密集型和CPU密集型两种.这两种的线程池的配置有很大的区别.以我们的另一个常见的‘池’,数据库连接池来说,一般设置连接数量,推荐公式是: n = cpu核数 * 2 + 磁盘数 对于线程池来说网上是有很多的参考:


我自己使用一般: IO密集型 n = cpu数 * 2 + 磁盘数
CPU密集型 n = cpu数 + 磁盘数

大厂一般对线程池的使用情况是有监控的,对于他们的业务量很大的情况下,一般很难预估实际的参数,所以他们采用热部署,根据ThreadPoolExecutor提供的方法,可以做到动态参数化.

(参考:https://mp.weixin.qq.com/s/baYuX8aCwQ9PP6k7TDl2Ww)

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。