学自:
一、流程:
创建一个任务时,先判断线程池中已有的线程数是否已经超过核心线程数,如果没有,则创建任务;
如果超过核心线程数,去阻塞队列中,看阻塞队列是否已满,如果没满,则放入阻塞队列中;
如果阻塞队列已满,则判断当前线程数是否超过最大线程数,如果没超过,则创建一个新的线程;
如果超过最大线程数,则走异常处理流程(直接抛异常;不处理,丢弃;将阻塞队列中最早的任务丢弃,然后将其放入阻塞队列)
二、异常处理方法:
(一)线程池提交时submit:
1、try catch
2、用Future作为submit的结果,用future.get()方法,接收抛出的异常(future.get()方法要加try catch)
(二)线程中处理异常:
在工作线程的.setUnCaughtExceptionHandler(中处理未捕获到的异常)
Thread t = new Thread(r);
t.setUncaughtExceptionHandler(
(t1, e) -> {
System.out.println(t1.getName() + "线程抛出的异常"+e);
});
return t;
});
(三)重写ThreadExecutorPool的afterExecute方法 处理传递的异常引用!
三、线程池:
先码住:
newFixedTreadPool固定线程数线程池
-
核心线程数和最大线程数大小一样
-
没有所谓的非空闲时间,即keepAliveTime为0
-
阻塞队列为无界队列LinkedBlockingQueue
newCachedTreadPool(可缓存线程的线程池)
-
核心线程数为0
-
最大线程数为Integer.MAX_VALUE
-
阻塞队列是SynchronousQueue
-
非核心线程空闲存活时间为60秒
-
提交任务
-
因为没有核心线程,所以任务直接加到SynchronousQueue队列。
-
判断是否有空闲线程,如果有,就去取出任务执行。
-
如果没有空闲线程,就新建一个线程执行。
-
执行完任务的线程,还可以存活60秒,如果在这期间,接到任务,可以继续活下去;否则,被销毁
newSingleTreadExecutor单线程线程池
-
核心线程数为1
-
最大线程数也为1
-
阻塞队列是LinkedBlockingQueue
-
keepAliveTime为0
newScheduledThreadPool(定时及周期执行的线程池)
-
最大线程数为Integer.MAX_VALUE
-
阻塞队列是DelayedWorkQueue
-
keepAliveTime为0
-
scheduleAtFixedRate() :按某种速率周期执行
-
scheduleWithFixedDelay():在某个延迟后执行
工作机制
-
添加一个任务
-
线程池中的线程从 DelayQueue 中取任务
-
线程从 DelayQueue 中获取 time 大于等于当前时间的task
-
执行完后修改这个 task 的 time 为下次被执行的时间
-
这个 task 放回DelayQueue队列中