面试题线程池,java多线程面试题
如何解决写爬虫IP受阻的问题?立即使用。
下面是我整理的一些java面试中常见的线程池问题,现在分享给大家。
(学习视频分享:java教学视频)
什么是线程池?
线程池是多线程处理的一种形式,任务提交给线程池,任务的执行由线程池管理。
如果每个请求都通过创建一个线程来处理,那么服务器的资源将会很快耗尽。使用线程池可以减少创建和销毁线程的数量,并且每个工作线程可以重用来执行多个任务。
为什么要使用线程池?
创建和销毁线程的成本很高,可能比处理业务的时间还要长。如此频繁的线程创建和线程销毁,再加上业务工作线程花费的时间,可能会导致系统资源不足。(我们可以去掉创建和销毁线程的过程)
线程池的作用是什么?
线程池的作用是限制系统中执行线程的数量。
1.提高效率。创建一定数量的线程,并将它们放入池中。需要的时候从泳池里拿一个。这比在需要时创建线程对象要快得多。
2.管理方便。您可以编写线程池管理代码来管理池中的相同线程。例如,当程序启动时,它创建100个线程,每当有请求时,它就分配一个线程工作。如果只有101个并发请求,额外的请求可以排队,以避免由无休止的线程创建导致的系统崩溃。
说几个常见的线程池和使用场景。
1、新线程执行程序
创建一个单线程线程池,该线程池将只使用唯一的工作线程来执行任务,并确保所有任务都按照指定的顺序(FIFO、LIFO、priority)执行。
2、新固定线程池
创建一个固定长度的线程池来控制并发线程的最大数量,多余的线程将在队列中等待。
3、新缓存线程池
创建一个可缓存的线程池。如果线程池的长度超过了处理需要,可以灵活地回收空闲线程。如果没有回收,可以创建一个新线程。
4、新调度线程池
创建一个固定长度的线程池来支持计划的和定期的任务执行。
线程池中的几个重要参数
CorePoolSize是线程池中的核心线程数。这些核心线程只有在没用的时候才会被回收。
MaximumPoolSize是线程池中可以容纳的最大线程数。
KeepAliveTime是线程池中除了核心线程之外可以保持的最长时间,因为在线程池中,除了核心线程,即使没有任务也不能清除,其余的都有生存期,也就是说非核心线程可以保持的最长空闲时间。
Util是计算这个时间的单位。
工作队列是等待队列。任务可以存储在任务队列中,等待执行。实施FIFIO原则(先进先出)。
(分享更多相关面试问题:java面试问答)
ThreadFactory是创建线程的线程工厂。
Handler,是一种拒绝策略。任务满了之后我们可以拒绝执行某些任务。
谈线程池的拒绝策略
当请求任务不断到来,此时系统无法处理时,我们需要采取的策略就是拒绝服务。RejectedExecutionHandler接口提供了拒绝任务处理的自定义方法的机会。ThreadPoolExecutor已经包含了四种处理策略。
AbortPolicy policy:这个策略会直接抛出异常,阻止系统正常工作。
CallerRunsPolicy:只要线程池没有关闭,这个策略就直接在调用者的线程中运行当前丢弃的任务。
DiscardOleddestPolicy策略:该策略将丢弃最旧的请求,即要执行的任务,并尝试再次提交当前任务。
DiscardPolicy策略:此策略会自动丢弃无法处理的任务,并且根本不会处理这些任务。
除了JDK默认提供的四种拒绝策略外,我们还可以根据自己的业务需求定制拒绝策略。定制的方式很简单,直接实现RejectedExecutionHandler接口即可。
执行和提交的区别?
在前面的解释中,我们使用了execute方法来执行任务。除了execute方法,还有一个submit方法也可以执行我们提交的任务。
这两种方法有什么区别?它们适用于什么场景?我们来做一个简单的分析。
Execute适用于不需要关注返回值,只需要把线程扔进线程池执行的场景。
submit方法适用于需要注意返回值的场景。
五个线程池的使用场景
NewSingleThreadExecutor:单线程线程池,可用于需要顺序执行,而只有一个线程在执行的场景。
NewFixedThreadPool:一个固定大小的线程池,当并发压力已知时,可以用来限制线程的数量。
NewCachedThreadPool:可以无限扩展的线程池,比较适合处理执行时间相对较短的任务。
NewScheduledThreadPool:一个可以延迟和计时启动的线程池。它适用于需要多个后台线程来执行定期任务的情况。
NewWorkStealingPool:具有多个任务队列的线程池,可以减少连接数,用当前可用的cpu号创建线程并行执行。
线程池的关闭
关闭线程池可以通过调用shutdownNow和shutdown方法来实现。
ShutdownNow:向所有正在执行的任务发出interrupt(),停止执行,取消所有尚未开始的任务,返回尚未开始的任务列表。
Shutdown:当我们调用shutdown时,线程池将不再接受新任务,但不会强制终止已提交或正在执行的任务。
初始化线程池时线程号的选择
如果任务是IO密集型的,一般线程数应该设置为CPU数的2倍以上,这样才能充分利用CPU资源。
如果任务是CPU密集型的,一般线程数只需要按CPU加1来设置,更多的线程只能增加上下文切换,而不能增加CPU利用率。
以上只是一个基本思路。如果真的需要精确控制,还是需要观察线程池中线程的数量,以及上线后队列的情况。
线程有哪几种工作队列?
1、ArrayBlockingQueue
是基于数组结构的有界阻塞队列,按照FIFO(先进先出)原则对元素进行排序。
2、LinkedBlockingQueue
基于链表结构的阻塞队列,按照FIFO(先进先出)对元素进行排序,其吞吐量通常高于ArrayBlockingQueue。工厂方法Executors.newFixedThreadPool()使用这个队列。
3、同步队列
不存储元素的阻塞队列。每个插入操作都必须等到另一个线程调用移除操作,否则插入操作将始终被阻塞,吞吐量通常高于静态工厂方法Executors.newCachedThreadPool使用的LinkedBlockingQueue
4、优先级阻塞队列
具有优先级的无限阻塞队列。
相关课程推荐:java入门教程以上是java面试线程池的详细介绍。更多请关注我们的其他相关文章!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。