java线程池的⾯试题_java线程池⾯试题(精简)
什么是线程池?
线程池是⼀种多线程处理形式,处理过程中将任务提交到线程池,任务的执⾏交由线程池来管理。
如果每个请求都创建⼀个线程去处理,那么服务器的资源很快就会被耗尽,使⽤线程池可以减少创建和销毁线程的次数,每个⼯作线程都可以被重复利⽤,可执⾏多个任务。
为什么要使⽤线程池?
创建线程和销毁线程的花销是⽐较⼤的,这些时间有可能⽐处理业务的时间还要长。这样频繁的创建线程和销毁线程,再加上业务⼯作线程,消耗系统资源的时间,可能导致系统资源不⾜。(我们可以把创建和销毁的线程的过程去掉)
java线程池创建的四种线程池有什么作⽤?
线程池作⽤就是限制系统中执⾏线程的数量。
1、提⾼效率 创建好⼀定数量的线程放在池中,等需要使⽤的时候就从池中拿⼀个,这要⽐需要的时候创建⼀个线程对象要快的多。
2、⽅便管理 可以编写线程池管理代码对池中的线程同⼀进⾏管理,⽐如说启动时有该程序创建100个线程,每当有请求的时候,就分配⼀个线程去⼯作,如果刚好并发有101个请求,那多出的这⼀个请求可以排队等候,避免因⽆休⽌的创建线程导致系统崩溃。
说说⼏种常见的线程池及使⽤场景
1、newSingleThreadExecutor
创建⼀个单线程化的线程池,它只会⽤唯⼀的⼯作线程来执⾏任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执⾏。
2、newFixedThreadPool
创建⼀个定长线程池,可控制线程最⼤并发数,超出的线程会在队列中等待。
3、newCachedThreadPool
创建⼀个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若⽆可回收,则新建线程。
4、newScheduledThreadPool
创建⼀个定长线程池,⽀持定时及周期性任务执⾏。
线程池中的⼏种重要的参数
corePoolSize就是线程池中的核⼼线程数量,这⼏个核⼼线程,只是在没有⽤的时候,也不会被回收
maximumPoolSize就是线程池中可以容纳的最⼤线程的数量
keepAliveTime,就是线程池中除了核⼼线程之外的其他的最长可以保留的时间,因为在线程池中,除了核⼼线程即使在⽆任务的情况下也不能被清 除,其余的都是有存活时间的,意思就是⾮核⼼线程可以保留的最长的空闲时间,
util,就是计算这个时间的⼀个单位。
workQueue,就是等待队列,任务可以储存在任务队列中等待被执⾏,执⾏的是FIFIO原则(先进先出)。
threadFactory,就是创建线程的线程⼯⼚。
handler,是⼀种拒绝策略,我们可以在任务满了之后,拒绝执⾏某些任务。
说说线程池的拒绝策略
当请求任务不断的过来,⽽系统此时⼜处理不过来的时候,我们需要采取的策略是拒绝服务。RejectedExecutionHandler接⼝提供了拒绝任务处理的⾃定义⽅法的机会。在ThreadPoolExecutor中已经包含四种处理策略。
AbortPolicy策略:该策略会直接抛出异常,阻⽌系统正常⼯作。
CallerRunsPolicy 策略:只要线程池未关闭,该策略直接在调⽤者线程中,运⾏当前的被丢弃的任务。
DiscardOleddestPolicy策略: 该策略将丢弃最⽼的⼀个请求,也就是即将被执⾏的任务,并尝试再次提交当前任务。
DiscardPolicy策略:该策略默默的丢弃⽆法处理的任务,不予任何处理。
除了JDK默认提供的四种拒绝策略,我们可以根据⾃⼰的业务需求去⾃定义拒绝策略,⾃定义的⽅式很简单,直接实现RejectedExecutionHandler接⼝即可。
execute和submit的区别?
在前⾯的讲解中,我们执⾏任务是⽤的execute⽅法,除了execute⽅法,还有⼀个submit⽅法也可以执⾏我们提交的任务。
这两个⽅法有什么区别呢?分别适⽤于在什么场景下呢?我们来做⼀个简单的分析。
execute适⽤于不需要关注返回值的场景,只需要将线程丢到线程池中去执⾏就可以了。
submit⽅法适⽤于需要关注返回值的场景
五种线程池的使⽤场景
newSingleThreadExecutor:⼀个单线程的线程池,可以⽤于需要保证顺序执⾏的场景,并且只有⼀个线程在执⾏。
newFixedThreadPool:⼀个固定⼤⼩的线程池,可以⽤于已知并发压⼒的情况下,对线程数做限制。
newCachedThreadPool:⼀个可以⽆限扩⼤的线程池,⽐较适合处理执⾏时间⽐较⼩的任务。
newScheduledThreadPool:可以延时启动,定时启动的线程池,适⽤于需要多个后台线程执⾏周期任务的场景。
newWorkStealingPool:⼀个拥有多个任务队列的线程池,可以减少连接数,创建当前可⽤cpu数量的线程来并⾏执⾏。
线程池的关闭
关闭线程池可以调⽤shutdownNow和shutdown两个⽅法来实现
shutdownNow:对正在执⾏的任务全部发出interrupt(),停⽌执⾏,对还未开始执⾏的任务全部取消,并且返回还没开始的任务列表。
shutdown:当我们调⽤shutdown后,线程池将不再接受新的任务,但也不会去强制终⽌已经提交或者正在执⾏中的任务。
初始化线程池时线程数的选择
如果任务是IO密集型,⼀般线程数需要设置2倍CPU数以上,以此来尽量利⽤CPU资源。
如果任务是CPU密集型,⼀般线程数量只需要设置CPU数加1即可,更多的线程数也只能增加上下⽂切换,不能增加CPU利⽤率。
上述只是⼀个基本思想,如果真的需要精确的控制,还是需要上线以后观察线程池中线程数量跟队列的情况来定。
线程池都有哪⼏种⼯作队列
1、ArrayBlockingQueue
是⼀个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进⾏排序。
2、LinkedBlockingQueue
⼀个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要⾼于ArrayBlockingQueue。静态⼯⼚⽅法wFixedThreadPool()使⽤了这个队列
3、SynchronousQueue
⼀个不存储元素的阻塞队列。每个插⼊操作必须等到另⼀个线程调⽤移除操作,否则插⼊操作⼀直处于阻塞状态,吞吐量通常要⾼于LinkedBlockingQueue,静态⼯⼚⽅法wCachedThreadPool使⽤了这个队列。
4、PriorityBlockingQueue
⼀个具有优先级的⽆限阻塞队列。
池的作⽤:有效保证连接数量和效⽤
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论