前言
这周我投递出了简历,岗位是java后端开发工程师。这周美团面试官给我进行了面试。面试过程当中他问了线程池,今天详细讲一讲Java线程池。java
线程池
线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短期任务时建立与销毁线程的代价。面试
1start()建立必定数量的线程池,进行线程循环 2 3stop()中止全部线程循环,回收全部资源 4 5addTask()添加任务
Excutors建立线程池便捷方法以下:后端
1Executors.newFixedThreadPool(100);//建立固定大小的线程池 2Executors.newSingleThreadExecutor();//建立只有一个线程的线程池 3Executors.newCachedThreadPool();//建立一个不限线程数上限的线程池,任何提交的任务都将当即执行
对于服务端须要长期运行的程序,建立线程池应该使用ThreadPoolExecutor
的构造方法缓存
1public ThreadPoolExecutor( 2 int corePoolPoolSize,//线程池长期维持的线程数 3 int maximumPoolSize, //线程数的上限 4 long keepAliveTime,//空闲线程存活时间 5 TimeUnit unit,//时间单位 6 BlockingQueue<Runnable> workQueue,//任务的排队队列 7 ThreadFactory threadFactory,//新线程的产生方式 8 RejectedExecutionHandler handler//拒绝策略 9 )
java线程池有7大参数,4大特性。服务器
特性一:当池中正在运行的线程数(包括空闲线程)小于corePoolSize时,新建线程执行任务。多线程
特性二:当池中正在运行的线程数大于等于corePoolSize时,新插入的任务进入workQueue排队(若是workQueue长度容许),等待空闲线程来执行。并发
特性三:当队列里的任务数达到上限,而且池中正在运行的线程数小于maximumPoolSize,对于新加入的任务,新建线程。less
特性四:当队列里的任务数达到上限,而且池中正在运行的线程数等于maximumPoolSize,对于新加入的任务,执行拒绝策略(线程池默认的拒绝策略是抛异常)。spa
种类
newCachedThreadPool操作系统
- 核心线程数为0,最大线程数为
Integer.MAX_VALUE
1public static ExecutorService newCachedThreadPool() { 2 return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 3 60L, TimeUnit.SECONDS, 4 new SynchronousQueue<Runnable>()); 5 }
做用
建立一个可根据须要建立新线程的线程池,可是在之前构造的线程可用时将重用它们,并在须要时使用提供的 ThreadFactory 建立新线程。
特征
(1)线程池中数量没有固定,可达到最大值(Interger. MAX_VALUE)
(2)线程池中的线程可进行缓存重复利用和回收(回收默认时间为1分钟)
(3)当线程池中,没有可用线程,会从新建立一个线程
建立方式
Executors.newCachedThreadPool();
newFixedThreadPool
- 核心线程数与最大线程数均为指定的nThreads
- 空闲线程的存活时间是0
- 工做队列是无界队列
1public static ExecutorService newFixedThreadPool(int nThreads) { 2 return new ThreadPoolExecutor(nThreads, nThreads, 3 0L, TimeUnit.MILLISECONDS, 4 new LinkedBlockingQueue<Runnable>()); 5 }
做用
建立一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。在任意点,在大多数 nThreads 线程会处于处理任务的活动状态。若是在全部线程处于活动状态时提交附加任务,则在有可用线程以前,附加任务将在队列中等待。若是在关闭前的执行期间因为失败而致使任何线程终止,那么一个新线程将代替它执行后续的任务(若是须要)。在某个线程被显式地关闭以前,池中的线程将一直存在。
特征
(1)线程池中的线程处于必定的量,能够很好的控制线程的并发量
(2)线程能够重复被使用,在显示关闭以前,都将一直存在
(3)超出必定量的线程被提交时候需在队列中等待
建立方式
1(1)Executors.newFixedThreadPool(int nThreads);//nThreads为线程的数量 2(2)Executors.newFixedThreadPool(int nThreads,ThreadFactory threadFactory);//nThreads为线程的数量,threadFactory建立线程的工厂方式
newSingleThreadExecutor
- 核心线程数与最大线程数均为1
- 工做队列是无界队列
1public static ExecutorService newSingleThreadExecutor() { 2 return new FinalizableDelegatedExecutorService 3 (new ThreadPoolExecutor(1, 1, 4 0L, TimeUnit.MILLISECONDS, 5 new LinkedBlockingQueue<Runnable>())); 6 }
做用
建立一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。(注意,若是由于在关闭前的执行期间出现失败而终止了此单个线程,那么若是须要,一个新线程将代替它执行后续的任务)。可保证顺序地执行各个任务,而且在任意给定的时间不会有多个线程是活动的。与其余等效的 newFixedThreadPool(1) 不一样,可保证无需从新配置此方法所返回的执行程序便可使用其余的线程。
特征
线程池中最多执行1个线程,以后提交的线程活动将会排在队列中以此执行。
建立方式
1(1)Executors.newSingleThreadExecutor() ; 2(2)Executors.newSingleThreadExecutor(ThreadFactory threadFactory);// threadFactory建立线程的工厂方式
newScheduledThreadPool
- 指定核心线程数corePoolSize
- 最大线程数是Integer.MAX_VALUE
- DelayedWorkQueue:任务队列会根据任务延时时间的优先级进行执行
1public class ScheduledThreadPoolExecutor 2 extends ThreadPoolExecutor 3 implements ScheduledExecutorService { 4 .................... 5 /** 6 * Creates a new {@code ScheduledThreadPoolExecutor} with the 7 * given core pool size. 8 * 9 * @param corePoolSize the number of threads to keep in the pool, even 10 * if they are idle, unless {@code allowCoreThreadTimeOut} is set 11 * @throws IllegalArgumentException if {@code corePoolSize < 0} 12 */ 13 public ScheduledThreadPoolExecutor(int corePoolSize) { 14 super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, 15 new DelayedWorkQueue()); 16 } 17 ....................... 18}
做用
建立一个线程池,它可安排在给定延迟后运行命令或者按期地执行。
特征
(1)线程池中具备指定数量的线程,即使是空线程也将保留
(2)可定时或者延迟执行线程活动
建立方式
1(1)Executors.newScheduledThreadPool(int corePoolSize);// corePoolSize线程的个数 2(2)newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory);// corePoolSize线程的个数,threadFactory建立线程的工厂
newSingleThreadScheduledExecutor
做用
建立一个单线程执行程序,它可安排在给定延迟后运行命令或者按期地执行。
特征
(1)线程池中最多执行1个线程,以后提交的线程活动将会排在队列中以此执行
(2)可定时或者延迟执行线程活动
建立方式
1(1)Executors.newSingleThreadScheduledExecutor() ; 2(2)Executors.newSingleThreadScheduledExecutor(ThreadFactory threadFactory);//threadFactory建立线程的工厂
工做队列
SynchronousQueue:直接提交
是工做队列的默认选项,将任务直接提交给线程而不保持。
若是不存在可用于当即运行任务的线程,则试图把任务加入队列将失败,所以会构造一个新的线程。
优缺点
优势:能够避免在处理可能具备内部依赖性的请求集时出现锁。
直接提交一般要求无界maximumPoolSizes 以免拒绝新提交的任务。
当命令以超过队列所能处理的平均数连续到达时,此策略容许无界线程具备增加的可能性。
ArrayBlockingQueue:无界队列
在全部核心线程都忙时,新任务在队列中等待。
所以,仅建立corePoolSize线程便可。(maximumPoolSize的值没有任何做用。)
当每一个任务彻底独立于其余任务时,所以任务不会影响彼此的执行。
优缺点
优势:例如,在网页服务器中,尽管这种排队方式对于消除短暂的突发请求颇有用。
缺点:当命令请求到达速度比其处理速度更快时,工做队列无限制增加。
LinkedBlockingQueue:有界队列
当与有限的maximumPoolSizes一块儿使用时,有界队列有助于防止资源耗尽,可是调整和控制起来会更加困难。
队列大小和最大池大小能够相互权衡
- 使用大队列和小池能够最大程度地减小CPU使用率,操做系统资源和上下文切换开销,但可能致使人为地下降吞吐量。
- 若是任务频繁阻塞(例如若是它们是受I/O约束的),则系统可能能够为非预约的更多线程安排时间。
- 使用小队列一般须要更大的池大小,这会使CPU繁忙,但可能会遇到不可接受的调度开销,这也会下降吞吐量。
拒绝策略
AbortPolicy:处理程序遭到拒绝将抛出运行时 RejectedExecutionException
DiscardPolicy:不能执行的任务将被删除
DiscardOldestPolicy:若是执行程序还没有关闭,则位于工做队列头部的任务将被删除,而后重试执行程序(若是再次失败,则重复此过程)
CallerRunsPolicy:线程调用运行该任务的 execute 自己。此策略提供简单的反馈控制机制,可以减缓新任务的提交速度。
1RejectedExecutionHandler rejected = null; 2 3rejected = new ThreadPoolExecutor.AbortPolicy();//默认,队列满了丢任务抛出异常 4 5rejected = new ThreadPoolExecutor.DiscardPolicy();//队列满了丢任务不异常 6 7rejected = new ThreadPoolExecutor.DiscardOldestPolicy();//将最先进入队列的任务删,以后再尝试加入队列 8 9rejected = new ThreadPoolExecutor.CallerRunsPolicy();//若是添加到线程池失败,那么主线程会本身去执行该任务
总结
我们玩归玩,闹归闹,别拿面试开玩笑。
线程池记忆口诀:七个参数,四大特性,五个种类、三大工做队列、四大拒绝策略
线程池,在面试中出现的次数很是多,你们面试前要把知识点记牢。