• 如果外包员工把需求做完了,它经过一段(keepAliveTime)空闲时间,就离开公司了。

好的,到这里。面试问题1->Java的线程池说一下,各个参数的作用,如何进行的? 是否已经迎刃而解啦, 我觉得这个问题,回答:线程池构造函数的corePoolSize,maximumPoolSize等参数,并且能描述清楚线程池的执行流程 就差不多啦。

线程池异常处理


在使用线程池处理任务的时候,任务代码可能抛出RuntimeException,抛出异常后,线程池可能捕获它,也可能创建一个新的线程来代替异常的线程,我们可能无法感知任务出现了异常,因此我们需要考虑线程池异常情况。

当提交新任务时,异常如何处理?

我们先来看一段代码:

ExecutorService threadPool = Executors.newFixedThreadPool(5);for (int i = 0; i < 5; i++) {threadPool.submit(() -> {System.out.println("current thread name" + Thread.currentThread().getName());Object object = null;System.out.print("result## "+object.toString());});}

显然,这段代码会有异常,我们再来看看执行结果

虽然没有结果输出,但是没有抛出异常,所以我们无法感知任务出现了异常,所以需要添加try/catch。 如下图:

OK,线程的异常处理,我们可以直接try…catch捕获。

线程池exec.submit(runnable)的执行流程

通过debug上面有异常的submit方法(建议大家也去debug看一下,图上的每个方法内部是我打断点的地方),处理有异常submit方法的主要执行流程图:

//构造feature对象/*** @throws RejectedExecutionException {@inheritDoc}* @throws NullPointerException       {@inheritDoc}*/public Future<?> submit(Runnable task) {if (task == null) throw new NullPointerException();RunnableFuture<Void> ftask = newTaskFor(task, null);execute(ftask);return ftask;}protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {return new FutureTask<T>(runnable, value);}public FutureTask(Runnable runnable, V result) {this.callable = Executors.callable(runnable, result);this.state = NEW;       // ensure visibility of callable}public static <T> Callable<T> callable(Runnable task, T result) {if (task == null)throw new NullPointerException();return new RunnableAdapter<T>(task, result);}//线程池执行public void execute(Runnable command) {if (command == null)throw new NullPointerException();int c = ctl.get();if (workerCountOf(c) < corePoolSize) {if (addWorker(command, true))return;c = ctl.get();}if (isRunning(c) && workQueue.offer(command)) {int recheck = ctl.get();if (! isRunning(recheck) && remove(command))reject(command);else if (workerCountOf(recheck) == 0)addWorker(null, false);}else if (!addWorker(command, false))reject(command);}//捕获异常public void run() {if (state != NEW ||!UNSAFE.compareAndSwapObject(this, runnerOffset,null, Thread.currentThread()))return;try {Callable<V> c = callable;if (c != null && state == NEW) {V result;boolean ran;try {result = c.call();ran = true;} catch (Throwable ex) {result = null;ran = false;setException(ex);}if (ran)set(result);}} finally {// runner must be non-null until state is settled to// prevent concurrent calls to run()runner = null;// state must be re-read after nulling runner to prevent// leaked interruptsint s = state;if (s >= INTERRUPTING)handlePossibleCancellationInterrupt(s);}

通过以上分析,submit执行的任务,可以通过Future对象的get方法接收抛出的异常,再进行处理。 我们再通过一个demo,看一下Future对象的get方法处理异常的姿势,如下图:

其他两种处理线程池异常方案

除了以上1.在任务代码try/catch捕获异常,2.通过Future对象的get方法接收抛出的异常,再处理两种方案外,还有以上两种方案:

3.为工作者线程设置UncaughtExceptionHandler,在uncaughtException方法中处理异常

我们直接看这样实现的正确姿势:


ExecutorService threadPool = Executors.newFixedThreadPool(1, r -> {Thread t = new Thread(r);t.setUncaughtExceptionHandler((t1, e) -> {System.out.println(t1.getName() + "线程抛出的异常"+e);});return t;});threadPool.execute(()->{Object object = null;System.out.print("result## " + object.toString());});

运行结果:

4.重写ThreadPoolExecutor的afterExecute方法,处理传递的异常引用

这是jdk文档的一个demo:


class ExtendedExecutor extends ThreadPoolExecutor {// 这可是jdk文档里面给的例子。。protected void afterExecute(Runnable r, Throwable t) {super.afterExecute(r, t);if (t == null && r instanceof Future<?>) {try {Object result = ((Future<?>) r).get();} catch (CancellationException ce) {t = ce;} catch (ExecutionException ee) {t = ee.getCause();} catch (InterruptedException ie) {Thread.currentThread().interrupt(); // ignore/reset}}if (t != null)System.out.println(t);}}}

因此,被问到线程池异常处理,如何回答?

线程池的工作队列


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

  • ArrayBlockingQueue

  • LinkedBlockingQueue

  • DelayQueue

  • PriorityBlockingQueue

  • SynchronousQueue

ArrayBlockingQueue

ArrayBlockingQueue(有界队列)是一个用数组实现的有界阻塞队列,按FIFO排序量。

LinkedBlockingQueue

LinkedBlockingQueue(可设置容量队列)基于链表结构的阻塞队列,按FIFO排序任务,容量可以选择进行设置,不设置的话,将是一个无边界的阻塞队列,最大长度为Integer.MAX_VALUE,吞吐量通常要高于ArrayBlockingQuene;newFixedThreadPool线程池使用了这个队列

DelayQueue

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

PriorityBlockingQueue

PriorityBlockingQueue(优先级队列)是具有优先级的无界阻塞队列;

SynchronousQueue

SynchronousQueue(同步队列)一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQuene,newCachedThreadPool线程池使用了这个队列。

针对面试题:线程池都有哪几种工作队列? 我觉得,回答以上几种ArrayBlockingQueue,LinkedBlockingQueue,SynchronousQueue等,说出它们的特点,并结合使用到对应队列的常用线程池(如newFixedThreadPool线程池使用LinkedBlockingQueue),进行展开阐述, 就可以啦。

几种常用的线程池


  • newFixedThreadPool (固定数目线程的线程池)

  • newCachedThreadPool(可缓存线程的线程池)

  • newSingleThreadExecutor(单线程的线程池)

  • newScheduledThreadPool(定时及周期执行的线程池)

newFixedThreadPool

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

线程池特点:

  • 核心线程数和最大线程数大小一样

  • 没有所谓的非空闲时间,即keepAliveTime为0

  • 阻塞队列为无界队列LinkedBlockingQueue

工作机制:

  • 提交任务

  • 如果线程数少于核心线程,创建核心线程执行任务

  • 如果线程数等于核心线程,把任务添加到LinkedBlockingQueue阻塞队列

  • 如果线程执行完任务,去阻塞队列取任务,继续执行。

实例代码

ExecutorService executor = Executors.newFixedThreadPool(10);for (int i = 0; i < Integer.MAX_VALUE; i++) {executor.execute(()->{try {Thread.sleep(10000);} catch (InterruptedException e) {//do nothing}});

IDE指定JVM参数:-Xmx8m -Xms8m :

run以上代码,会抛出OOM:

因此,面试题:使用无界队列的线程池会导致内存飙升吗?

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

使用场景

FixedThreadPool 适用于处理CPU密集型的任务,确保CPU在长期被工作线程使用的情况下,尽可能的少的分配线程,即适用执行长期的任务。

newCachedThreadPool

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

线程池特点:

  • 核心线程数为0

  • 最大线程数为Integer.MAX_VALUE

  • 阻塞队列是SynchronousQueue

  • 非核心线程空闲存活时间为60秒

当提交任务的速度大于处理任务的速度时,每次提交一个任务,就必然会创建一个线程。极端情况下会创建过多的线程,耗尽 CPU 和内存资源。由于空闲 60 秒的线程会被终止,长时间保持空闲的 CachedThreadPool 不会占用任何资源。

工作机制

  • 提交任务

  • 因为没有核心线程,所以任务直接加到SynchronousQueue队列。

  • 判断是否有空闲线程,如果有,就去取出任务执行。

  • 如果没有空闲线程,就新建一个线程执行。

  • 执行完任务的线程,还可以存活60秒,如果在这期间,接到任务,可以继续活下去;否则,被销毁。

实例代码

ExecutorService executor = Executors.newCachedThreadPool();for (int i = 0; i < 5; i++) {executor.execute(() -> {System.out.println(Thread.currentThread().getName()+"正在执行");});}

运行结果:

使用场景

用于并发执行大量短期的小任务。

newSingleThreadExecutor

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

线程池特点

  • 核心线程数为1

  • 最大线程数也为1

  • 阻塞队列是LinkedBlockingQueue

  • keepAliveTime为0

工作机制

  • 提交任务

  • 线程池是否有一条线程在,如果没有,新建线程执行任务

  • 如果有,讲任务加到阻塞队列

  • 当前的唯一线程,从队列取任务,执行完一个,再继续取,一个人(一条线程)夜以继日地干活。

实例代码

ExecutorService executor = Executors.newSingleThreadExecutor();for (int i = 0; i < 5; i++) {executor.execute(() -> {System.out.println(Thread.currentThread().getName()+"正在执行");});}

运行结果:

使用场景

适用于串行执行任务的场景,一个任务一个任务地执行。

newScheduledThreadPool

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

线程池特点

  • 最大线程数为Integer.MAX_VALUE

  • 阻塞队列是DelayedWorkQueue

  • keepAliveTime为0

  • scheduleAtFixedRate() :按某种速率周期执行

  • scheduleWithFixedDelay():在某个延迟后执行

工作机制

  • 添加一个任务

  • 线程池中的线程从 DelayQueue 中取任务

  • 线程从 DelayQueue 中获取 time 大于等于当前时间的task

  • 执行完后修改这个 task 的 time 为下次被执行的时间

总结

如果你选择了IT行业并坚定的走下去,这个方向肯定是没有一丝问题的,这是个高薪行业,但是高薪是凭自己的努力学习获取来的,这次我把P8大佬用过的一些学习笔记(pdf)都整理在本文中了,如果你有需要的话,请一定点赞分享本文

CodeChina开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频】

《Java中高级核心知识全面解析》

小米商场项目实战,别再担心面试没有实战项目:

tor(int corePoolSize) {

    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,new DelayedWorkQueue());}
线程池特点*   最大线程数为Integer.MAX\_VALUE*   阻塞队列是DelayedWorkQueue*   keepAliveTime为0*   scheduleAtFixedRate() :按某种速率周期执行*   scheduleWithFixedDelay():在某个延迟后执行工作机制*   添加一个任务*   线程池中的线程从 DelayQueue 中取任务*   线程从 DelayQueue 中获取 time 大于等于当前时间的task*   执行完后修改这个 task 的 time 为下次被执行的时间# 总结如果你选择了IT行业并坚定的走下去,这个方向肯定是没有一丝问题的,这是个高薪行业,但是高薪是凭自己的努力学习获取来的,这次我把P8大佬用过的一些学习笔记(pdf)都整理在本文中了,如果你有需要的话,请一定**点赞分享本文****[CodeChina开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频】](https://codechina.csdn.net/m0_60958482/java-p7)****《Java中高级核心知识全面解析》**[外链图片转存中...(img-SH4Nlgaj-1630662432518)]**小米商场项目实战,别再担心面试没有实战项目:**![](https://img-blog.csdnimg.cn/img_convert/ce5f65759882b907654d6d54eecc91da.png)

【BAT面试题系列,网易Java社招面试题相关推荐

  1. 小米java面试题_小米java社招面试题分享,面经(一面二面)

    下面给大家带来的是小米java社招面试题(面经)的相关分享,主要包括了一面二面的面试题,准备小米java一面二面的小伙伴可以来了解一下. 注:面试者是跨行做后台,没有什么项目经验,所以,面试者问的东西 ...

  2. 小米java社招面试题分享,面经(一面二面)

    下面给大家带来的是小米java社招面试题(面经)的相关分享,主要包括了一面二面的面试题,准备小米java一面二面的小伙伴可以来了解一下. 注:面试者是跨行做后台,没有什么项目经验,所以,面试者问的东西 ...

  3. 网易 java社招面试_《最新面经》—网易Java岗社招面试经历分享

    (面试题+答案领取方式:关注公众号回复[666]) 网易面试题 1. 面向对象的特点有哪些? 2. 列举几个java常用的package及其作用 3. 接口和抽象类有什么联系和区别 4. 重载和重写有 ...

  4. 网易 java社招面试_十月底—最新网易Java岗社招面试经历分享

    image (面试题+答案领取方式:关注公众号白楠楠获取) 网易面试题 面向对象的特点有哪些? 列举几个java常用的package及其作用 接口和抽象类有什么联系和区别 重载和重写有什么区别 jav ...

  5. 2021年Java社招面试题,2021大厂面试合集

    前言 前几日有个小老弟找我哭诉,挤破脑袋进Alibaba,三轮技术下来倒在了**缓存技术(Redis+MongDB)**上.听完我这小老弟的一番肺腑之言,这-缓存架构技术:Redis+MongDB,不 ...

  6. 网易 java社招面试_一个妹子网易Java岗社招面试经历分享

    博客群发软件--用 Windows Live Writer完美发布新浪网易blogcnbl 博客群发软件--用 Windows Live Writer完美发布新浪.网易.blogcn.blogbus. ...

  7. 快手Java社招面试题解析

    快手一面 1.要不先做下自我介绍?说一说你最近做的那个项目?然后针对简历提了几个问题 2.mysql 我看你简历里面说做过mysql的优化,说说你都做过哪些优化或者优化的思路? 数据库的索引了解吗?说 ...

  8. 网易Java社招面试

    •写一些类似行测里面的看图选规则之类的题目 •查找出目前正在运行的TCP/UDP服务 •查找出文件test中的所有含"apa"的单词,并保存到文件testc中 •List.Vect ...

  9. 【面试题系列】Java多线程常见面试题

    目录 序言 问题 1.Java中的线程有哪些状态,它们之间是如何转换的? 2.什么是Java中的线程安全?怎么实现 3.Java中线程的创建方法有哪些 3.1 继承Thread类并覆盖run()方法 ...

最新文章

  1. python格式化文本_Python格式化大文本
  2. l3fwd 是什么_服务器DPDK l3fwd性能测试
  3. iOS程序员眼中的客户端免登陆(数据迁移已更新)
  4. 怀旧服新开服务器最新,暴雪官方发大招,怀旧服新开11个新服务器
  5. vmware提示com.vmware.sps.fault.QsConnectionException报错
  6. Java Web(5) Spring 下使用Junit4 单元测试
  7. CSS+JS灰色树型菜单导航代码
  8. 异步解耦_如何使用异步生成器解耦业务逻辑
  9. CSS Grid布局(3)
  10. Sql Server 学习2
  11. 怎样将一个Long类型的数据转换成字节数组
  12. Python 3.9.5 官方中文文档及打包下载
  13. 卓有成效的管理者(笔记)——如何发挥人的长处
  14. 觅风易语言智能辅助开发视频教程(高清带源码)
  15. 谈谈AVG游戏的Android移植(NScripter与吉里吉里)
  16. 计算机电源 自动关机,电脑自动关机是什么原因,小编教你怎么解决电脑自动关机...
  17. pcl命名空间:segmentation/extract_clusters.h与segmentation/imp/extract_clusters.hpp
  18. 基于python的图像灰度值处理(opencv)
  19. 安卓怎么转移到iphone_如何将联系人从iPhone转移到另一部电话
  20. Android初学之十二:Broadcast

热门文章

  1. 了解OpenCart中的地理区域和税收
  2. 周鸿祎:令人激动无比的第四次工业革命即将到来(转)
  3. Sikuli 优缺点
  4. DNS被劫持有那些症状?dns被劫持怎么解决如何处理
  5. calicoctl命令简介
  6. excel插入图片自动适应表格大小
  7. 计算机网络应用层测试
  8. 基于浪潮“源1.0”的AI反诈项目:看高智商AI如何反杀诈骗犯
  9. 华为MU609调试记录
  10. Hssfworkbook 设置单元格格式 setdataformat