前言
共7题。
线程池的执行流程?
当我们提交一个任务到线程池中,线程池的处理流程大致如下:
-
首先判断线程池里的核心线程数是否已满,如果没满,则创建一个新的核心线程来执行任务;
-
如果核心线程满了,则判断工作队列是否已满,如果没满,则将新提交的任务存储在这个工作队列里;
-
如果工作队列满了,则判断最大线程数是否已满,如果没满,则创建临时线程直接执行任务;
-
如果最大线程数满了,则会执行对应的拒绝策略。
线程池的核心参数?
线程池在创建的时候最大支持传入7个参数,分别是:
-
核心线程数;
-
最大线程数;
-
临时线程存活时间;
-
临时线程的存活的时间单位(秒、分、时、天);
-
工作队列:用来保存等待执行的任务的;
-
ThreadFactory:设置创建线程的工厂; -
Handler:线程池的拒绝策略。
线程池的拒绝策略有哪些?
拒绝策略是指将任务添加到线程池中时,线程池拒绝该任务所采取的相应策略,官方提供的有4种:
-
AbortPolicy:直接抛出异常,默认策略; -
CallerRunsPolicy:用调用者所在的线程来执行任务; -
DiscardOldestPolicy:丢弃阻塞队列中靠最前的任务,并执行当前任务; -
DiscardPolicy:直接丢弃任务。
线程池的阻塞队列有哪些?
阻塞队列指的是当线程中核心线程数已满,新任务到达时,存储线程的队列,常见的有下面几种:
-
ArrayBlockingQueue:基于数组结构的有界阻塞队列; -
LinkedBlockingQueue:基于链表结构的有界阻塞队列; -
PriorityBlockingQueue:具有优先级别的阻塞队列; -
SynchronousQueue:不存储元素的阻塞队列,每个插入操作都必须等待一个移出操作。
submit和execute方法的区别?
都是线程池中用于提交线程任务的方法,区别点在于:
-
两个方法的参数都可以是
Runnable对象;submit方法的参数还可以是Callable对象。 -
submit可以返回一个Future对象,从这个对象中可以拿到线程运行结果,execute没有返回值。 -
submit能够控制异常,在主线程中通过Future的get方法捕获线程中的异常;execute不可以。
了解Executors创建线程池吗?
Excutors是JDK提供的一个可以创建线程池的工具类,可以直接创建出四种:
-
创建单线程化的线程池;
-
创建一个定长线程池;
-
创建一个可缓存的线程池;
-
创建固定大小的线程,延迟或定时执行任务。
但是用它创建的线程池有的没有限制最大线程数,有的没有限制阻塞队列的长度,这样的话,极大可能导致OOM(内存用完了),因此实际不常用,大部分时候还是使用自己传递参数的方式创建线程池。
如何确定线程池的核心线程数和最大线程数?
有两种情况,任务可能是CPU密集型(大部分时间都在进行运算)或IO密集型(大部分时间都在等待I/O操作):
-
如果是
CPU密集型,核心线程数可以设置为CPU核数+1; -
如果是
IO密集型,核心线程数可以设置为CPU核数的2倍。
最大线程数与核心线程数相同或稍大。