线程池
1.深入理解线程池
1.1 常用线程池体系结构
- Executor:线程池顶级接口
- ExecutorService:线程池次级接口
- AbstractExecutorService:抽象类,运用模板犯法设计模式实现了一部分算法
- ScheduledExecutorService:接口功能加强
- ForkJoinPool:新型线程池类,基于工作窃取理论实现,运用于大任务拆小任务,任务无限多的场景
- ThreadPoolExecutor:普通线程池类,包含最基本的一些线程池操作相关的方法
- ScheduledThreadPoolExecutor:定时任务线程池类,用于实现定时任务相关功能
- Executors: 线程池工具类,定义了一些快速实现线程池的方法
1.2 ExecutorService
扩展了 Executor的方法
1.3 AbstractExecutorService
AbstractExecutorService:抽象类,运用模板方法设计模式实现了一部分算法
1.3.1 submit
提交
public Future<?> submit(Runnable task) {
if (task == null) {
throw new NullPointerException();
} else {
// newTaskFor 实际上是实例了一个 runable + future 对象,使其可以执行,也可以将结果返回
RunnableFuture<Void> ftask = this.newTaskFor(task, (Object)null);
// 后续调用execute
this.execute(ftask);
return ftask;
}
}
1.3.2 invokeAny
只执行完成其中一个
具体实现是由 doInvokeAny实现
源码如下:
private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks, boolean timed, long nanos) throws InterruptedException, ExecutionException, TimeoutException {
// 日常判空
if (tasks == null) {
throw new NullPointerException();
} else {
// 任务数
int ntasks = tasks.size();
if (ntasks == 0) {
throw new IllegalArgumentException();
} else {
// 将任务放到一个数组中
ArrayList<Future<T>> futures = new ArrayList(ntasks);
// 生成一个 LinkedBlockingQueue
ExecutorCompletionService ecs = new ExecutorCompletionService(this);
try {
ExecutionException ee = null;
// 计算超时时限 (如果使用invokeany(,时限))
long deadline = timed ? System.nanoTime() + nanos : 0L;
// 任务迭代器读取
Iterator<? extends Callable<T>> it = tasks.iterator();
// 将迭代器获取的任务放到LinkedBlokingQueue,并放到数组中
futures.add(ecs.submit((Callable)it.next()));
// 任务数--
--ntasks;
// 执行中/活动中的任务赋值为1
int active = 1;
while(true) {
// 将刚刚放到Queue中的任务拿出来
Future<T> f = ecs.poll();
// 如果完成队列中没有任务结束
if (f == null) {
// 还有任务需要做
if (ntasks > 0) {
// 这里如果任务一直不执行成功的话,就会一直往队列中放,直到所有任务都放进去,执行
// 任务数 --
--ntasks;
// 任务进队列
futures.add(ecs.submit((Callable)it.next()));
// 活动数 ++
++active;
} else {
// 没有任务了
if (active == 0) {
// 活动中的任务也为0
if (ee == null) {
ee = new ExecutionException();
}
// 抛出异常,因为能够进入这里,说明必定是有任务在执行的。但是此时活动中的任务为0
throw ee;
}
// 设置了超时时限
if (timed) {
// 按照时限去取
f = ecs.poll(nanos, TimeUnit.NANOSECONDS);
// 如果一个任务直接把所有时间都消耗了,那么就是超时了
if (f == null) {
throw new TimeoutException();
}
// 整体任务还剩多长时间
nanos = deadline - System.nanoTime();
} else {
// 没有设置超时时限,去看看有没有执行成功的消息,如果还是没有 则会一直循环
// 这里也能保证拿到的结果是只有一个任务产生的结果
f = ecs.take();
}
}
}
// 说明已经有任务执行成功了
if (f != null) {
// 活动数减少
--active;
try {
// 获取任务执行结果
Object var14 = f.get();
return var14;
} catch (ExecutionException var19) {
ee = var19;
} catch (RuntimeException var20) {
ee = new ExecutionException(var20);
}
}
}
} finally {
// 将其他任务取消
cancelAll(futures);
}
}
}
}
eg.
public class T_001_ThreadPoolExecutorDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(10);
ArrayList<Callable<Integer>> callableArrayList = Lists.newArrayList(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
TimeHelper.sleep(15);
return 1;
}
}, new Callable<Integer>() {
@Override
public Integer call() throws Exception {
TimeHelper.sleep(10);
return 2;
}
});
System.out.println(executorService.invokeAny(callableArrayList));
}
}
结果如下
1.线程1 线程2 放到线程池中
2.线程1 执行
3.线程2 执行
3.线程2睡眠10S后任务结束,
4.此时会触发 cancel(线程1)
5.cancel(线程1) 会抛出Interrupted异常
ExecutorCompletionService
public class ExecutorCompletionService<V> implements CompletionService<V>
public Future<V> submit(Runnable task, V result) {
if (task == null) {
throw new NullPointerException();
} else {
RunnableFuture<V> f = this.newTaskFor(task, result);\
// 包装一下 Task
this.executor.execute(new ExecutorCompletionService.QueueingFuture(f, this.completionQueue));
return f;
}
}
// 装饰者模式
private static class QueueingFuture<V> extends FutureTask<Void> {
private final Future<V> task;
private final BlockingQueue<Future<V>> completionQueue;
QueueingFuture(RunnableFuture<V> task, BlockingQueue<Future<V>> completionQueue) {
super(task, (Object)null);
this.task = task;
this.completionQueue = completionQueue;
}
// 任务执行完成会调用done
protected void done() {
this.completionQueue.add(this.task);
}
}
public interface CompletionService<V> {
Future<V> submit(Callable<V> var1);
Future<V> submit(Runnable var1, V var2);
Future<V> take() throws InterruptedException;
Future<V> poll();
Future<V> poll(long var1, TimeUnit var3) throws InterruptedException;
}
1.3.3 invokeAll
源码如下:
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException {
// 日常判空
if (tasks == null) {
throw new NullPointerException();
} else {
ArrayList futures = new ArrayList(tasks.size());
try {
Iterator var3 = tasks.iterator();
while(var3.hasNext()) {
Callable<T> t = (Callable)var3.next();
RunnableFuture<T> f = this.newTaskFor(t);
futures.add(f);
// 每个任务都执行
this.execute(f);
}
int i = 0;
for(int size = futures.size(); i < size; ++i) {
Future<T> f = (Future)futures.get(i);
if (!f.isDone()) {
try {
f.get();
} catch (ExecutionException | CancellationException var7) {
}
}
}
// 将结果返回
return futures;
} catch (Throwable var8) {
cancelAll(futures);
throw var8;
}
}
}
1.4 Executors
线程池工具类,定义了一些快速实现线程池的方法
线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。说明:Executors各个方法的弊端:
1)newFixedThreadPool和newSingleThreadExecutor: 主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至OOM。
2)newCachedThreadPool和newScheduledThreadPool: 主要问题是线程数最大数是Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至OOM。
// 主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至OOM。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue());
}
public static ExecutorService newSingleThreadExecutor() {
return new Executors.FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()));
}
// 线程最大数 为 Integer.MAX_VALUE
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, 2147483647, 60L, TimeUnit.SECONDS, new SynchronousQueue());
}
public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory) {
super(corePoolSize, 2147483647, 10L, TimeUnit.MILLISECONDS, new ScheduledThreadPoolExecutor.DelayedWorkQueue(), threadFactory);
}
1.5 ThreadPoolExecutor
1.5.1 原理:
1.5.2 参数内容
public ThreadPoolExecutor(int corePoolSize, // 核心线程数
int maximumPoolSize, // 最大线程数
long keepAliveTime, // 等待时间
TimeUnit unit, // 时间单位
// BlockingQueue
// 没有任务执行的时候,会阻塞线程,如果有任务需要执行,则唤醒线程
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory, // 线程工厂
RejectedExecutionHandler handler // 处理策略
) {
this.ctl = new AtomicInteger(ctlOf(-536870912, 0));
this.mainLock = new ReentrantLock();
this.workers = new HashSet();
this.termination = this.mainLock.newCondition();
if (corePoolSize >= 0 && maximumPoolSize > 0 && maximumPoolSize >= corePoolSize && keepAliveTime >= 0L) {
if (workQueue != null && threadFactory != null && handler != null) {
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
} else {
throw new NullPointerException();
}
} else {
throw new IllegumentException();
}
}
1.5.3 拒绝策略
AbortPolicy() 抛出reject异常 --默认
CallerRunsPolicy() 调用者执行
DiscardPolicy() 直接丢弃
DiscardOldestPolicy() 丢弃队列中最老的
public class T_002_ThreadPoolExecutorDemo {
public static void main(String[] args) {
int cps=1;
int mps=2;
int c = 5;
int size = mps + c;
// 核心线程1, 临时线程数1 , 等待60
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(cps, mps, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(c));
for (int i = 0; i < size; i++) {
threadPoolExecutor.execute(()->{
TimeHelper.sleep(10);
});
}
// reject 异常
threadPoolExecutor.execute(()->{
TimeHelper.sleep(1);
});
System.out.println("wait");
}
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(cps, mps, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(c), Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy());
for (int i = 0; i < size; i++) {
threadPoolExecutor.execute(() -> {
TimeHelper.sleep(10);
});
}
// 调用者自己执行
threadPoolExecutor.execute(() -> {
TimeHelper.sleep(1);
});
System.out.println("wait");
}
自定义拒绝策略
public class T004_ThreadPool_MyRejectHandler {
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(10,
10,
0L,
TimeUnit.SECONDS,
new LinkedBlockingDeque(),
Executors.defaultThreadFactory(),
new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
if (!executor.isShutdown()) {
System.out.println("满了 满了");
}
}
}
);
}
}
1.5.4 ThreadPool的5种状态
RUNNING:接受新任务和进程队列任务
SHUTDOWN : 不接受新任务,但是会执行已经进队列的任务
STOP:不接受新任务也不接受已经进队列的任务,并打断正在执行中的任务
TIDYING:所有任务终止,待处理任务数量为0,线程转换为TIDYING,将会执行terminated钩子函数
TERMINATED:terminated 执行完成
RUNNING -> SHUTDOWN 调用shutdown()方法
RINNING/SHUTDOWN -> STOP 调用shutdownNow()方法
SHUTDOWN -> TIDYING:队列和线程池为空
STOP->TIDYING: 线程池为空
TIDYING -> TERMINATED :钩子函数terminated()执行完成
public class T003_ThreadPoolState {
public static void main(String[] args) throws InterruptedException {
//ExecutorService executorService = Executors.newFixedThreadPool(1);
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
1,
1,
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingDeque<>(),
new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setDaemon(true);
return thread;
}
});
threadPoolExecutor.submit(()->{
System.out.println("hello");
TimeHelper.sleep(10);
System.out.println("exit");
});
// 如果执行 shutdown 会打印 hello exit
threadPoolExecutor.shutdown();
// 如果执行 shutdownNow ,则会抛出打断的异常
threadPoolExecutor.shutdownNow();
threadPoolExecutor.awaitTermination(1, TimeUnit.MINUTES);
}
}
1.5.5 源码分析
1.5.5.1 execute源码
public void execute(Runnable command) {
// 日常判空
if (command == null)
throw new NullPointerException();
/*
* Proceed in 3 steps:
*
* 1. If fewer than corePoolSize threads are running, try to
* start a new thread with the given command as its first
* task. The call to addWorker atomically checks runState and
* workerCount, and so prevents false alarms that would add
* threads when it shouldn't, by returning false.
*
* 2. If a task can be successfully queued, then we still need
* to double-check whether we should have added a thread
* (because existing ones died since last checking) or that
* the pool shut down since entry into this method. So we
* recheck state and if necessary roll back the enqueuing if
* stopped, or start a new thread if there are none.
*
* 3. If we cannot queue task, then we try to add a new
* thread. If it fails, we know we are shut down or saturated
* and so reject the task.
*/
int c = ctl.get();
// 当前执行线程数 < 核心线程
if (workerCountOf(c) < corePoolSize) {
// 添加核心线程执行任务
if (addWorker(command, true))
return;
// 重新获取下
c = ctl.get();
}
// 当前线程池的状态 为RUNNING 并且能够成功入队
if (isRunning(c) && workQueue.offer(command)) {
// 再重新获取
int recheck = ctl.get();
// 线程池 状态不为 RUNNING , 移出任务队列成功
if (! isRunning(recheck) && remove(command))
// 拒绝
reject(command);
// 资源全部释放了
else if (workerCountOf(recheck) == 0)
// 添加一个非核心线程执行任务
addWorker(null, false);
}
// 无法添加非核心线程数(到达了最大线程数)
else if (!addWorker(command, false))
// 拒绝
reject(command);
}
private boolean addWorker(Runnable firstTask, boolean core) {
retry: // 用于goto
for (;;) {
// 快照
int c = ctl.get();
// 运行时状态
int rs = runStateOf(c);
// Check if queue empty only if necessary.
/** return true
1.线程池正常执行 RUNNING
2.线程池SHUTDOWN 提交的任务不是新任务(队列中的任务) 工作队列不为空
*/
// 线程池关闭
if (rs >= SHUTDOWN &&
! (
// SHUTDOWN 不可接受外部任务,但是需要执行内部队列
rs == SHUTDOWN &&
// 该任务是不是新提交任务
firstTask == null &&
// 工作队列是否为空
! workQueue.isEmpty()))
return false; // 不添加worker了
for (;;) {
// 工作线程数量
int wc = workerCountOf(c);
// 工作线程数量 >= 最大容忍的量
if (wc >= CAPACITY ||
// 添加的为核心线程数 还是 非核心线程数
wc >= (core ? corePoolSize : maximumPoolSize))
return false; // 不允许添加了
// 能够添加
// CAS 的增加 任务线程数,如果增加成功 那么就可以跳出循环 接下去走
if (compareAndIncrementWorkerCount(c))
break retry; //
// 添加失败了 要重新处理 因为出现了线程竞争
c = ctl.get(); // Re-read ctl
// 如果当前线程池被关闭了,那么就没必要在这边了
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
// 创建了一个新的worker
w = new Worker(firstTask);
// 取出线程
final Thread t = w.thread;
if (t != null) {
//
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
// 会有多线程
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
int rs = runStateOf(ctl.get());
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
//private final HashSet<Worker> workers = new HashSet<Worker>();
workers.add(w);
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
// 启动线程
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
// 启动失败 会将执行任务数 减去
addWorkerFailed(w);
}
return workerStarted;
}
Worker:
/** Thread this worker is running in. Null if factory fails. */
final Thread thread;
/** Initial task to run. Possibly null. */
Runnable firstTask;
/** Per-thread task counter */
volatile long completedTasks;
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker 防止在runWoker之前被中断
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
// task = getTask() 不会抛出异常
while (task != null || (task = getTask()) != null) {
w.lock();
// If pool is stopping, ensure thread is interrupted;
// if not, ensure thread is not interrupted. This
// requires a recheck in second case to deal with
// shutdownNow race while clearing interrupt
// 线程池关闭 STOP TIDYING TERMINATED
if ( (runStateAtLeast(ctl.get(), STOP) ||
// RUNNING SHUTDOWN 过程中 线程打断
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
// 线程是否被中断过(清除标记位)
!wt.isInterrupted())
// 中断线程
wt.interrupt();
try {
// 执行前,执行后
beforeExecute(wt, task); // 发生异常 completedAbruptly = true
Throwable thrown = null;
try {
task.run();
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
// 线程池异常如何抛出
afterExecute(task, thrown); // 发生异常 completedAbruptly = true
}
} finally {
task = null;
// 完成任务数++
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
// 工作线程的死亡 是由于用户异常导致的
processWorkerExit(w, completedAbruptly);
}
}
private void processWorkerExit(Worker w, boolean completedAbruptly) {
if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
decrementWorkerCount(); // 减少工作线程数
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
completedTaskCount += w.completedTasks;
// hashSet中移除
workers.remove(w);
} finally {
mainLock.unlock();
}
tryTerminate();
int c = ctl.get();
// SHUTDOWN RUNNING
if (runStateLessThan(c, STOP)) {
// 是否用户线程导致的
if (!completedAbruptly) {
// 保证最起码有一个线程在执行
// 不是用户线程导致的
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
// 队列不为空
if (min == 0 && ! workQueue.isEmpty())
min = 1;
// 如果工作线程 < 1 那么就会 新起线程
if (workerCountOf(c) >= min)
return; // replacement not needed
}
// 用户异常造成的会新起一个非核心的任务线程
addWorker(null, false);
}
}
2. 关于线程池的常见问题
2.1 常见的线程池有哪些
2.1.1 newFixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) {
// 固定线程数的线程数,核心线程数 = 最大线程数
// 缺点:1.如果线程池中没有任务执行,核心线程不会释放资源,占用一定的系统资源
// 2.采用了LinkedBlockingQueue ,虽然有最大限制为 Integer.MAX_VALUE,也相当于是一个无界的 队列,容易造成OOM
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
2.1.2 newCachedThreadPool
public static ExecutorService newCachedThreadPool() {
// 核心线程数为0 ,最大线程数为 Integer.MAX_VALUE
// 这样做有个优点 就是,如果工作线程超过60S 没有任务执行,那么它会自动终止,终止后如果有新的任务,会重新创建新的进程,节省了资源
// 缺点: 可以创建很多个线程,可能会造成OOM
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
2.1.3 newScheduleThreadPool
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
// scheduleThreadPoolExecutor 继承了 ThreadPoolExecutor
public ScheduledThreadPoolExecutor(int corePoolSize) {
// 核心线程数为定长,最大线程数 为 Integer.MAX_VALUE
// 缺点也很明显,可以创建很多线程,可能造成OOM
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
2.1.4 newSingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
// 固定核心线程数为1 最大线程数为1
// 优点:单工作线程最大的特点是可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的
// 缺点:无界队列 可能会造成OOM
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
2.1.5 newWorkStealingPool
public static ExecutorService newWorkStealingPool() {
// 使用的是ForkJoin
return new ForkJoinPool
(Runtime.getRuntime().availableProcessors(),
ForkJoinPool.defaultForkJoinWorkerThreadFactory,
null, true);
}
// ForkJoinPool 主要用于实现“分而治之”的算法,特别是分治之后递归调用的函数,例如 quick sort 等。
总结:
常见的有:
定长的(newFixedThreadPool, newSingleThreadExecutor)这种一般都由于使用了LinkedBlockingQueue 这种无界队列,可能会造成OOM
特殊功能:newScheduleThreadPool 调度线程池
newCachedThreadPool 缓存线程池
缺点是 最大线程数为 Integer.MAX_VALUE 也可能造成OOM
2.2 阿里巴巴Java开发手册为什么不允许使用Executors的默认实现
通过2.1 以及 1.4 中的描述已经可以解决该问题
线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。说明:Executors各个方法的弊端:
1)newFixedThreadPool和newSingleThreadExecutor: 主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至OOM。
2)newCachedThreadPool和newScheduledThreadPool: 主要问题是线程数最大数是Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至OOM。
2.3 自定义线程池(自定义线程池参数、参数设置的依据)
线程池参数: 如 1.5.2 描述一致
corepoolsize: 核心线程数 -> 不会释放资源
maxpoolsize: 最大线程数 -> 可以创建的最大线程数
keepalivetime: 线程留存时间 -> 临时线程执行完成后,可以待多长时间(因为临时线程是需要释放资源的)
TIMEUNIT : 留存时间单位
workQueue:工作队列
ThreadFactory:线程工厂
rejectHandler: 拒绝策略
2.4 自定义线程池完了,描述下这个线程池的工作流程
可以参考1.5.5.1
队列中的线程是什么时候被调用的?
其实 在 执行 t.start() 会调用 RunWork.run()
具体源码可以参照 1.5.5.1中的 runWorker方法
执行时 会判断 队列中是否为空 task = getTask(),此时就会把队列中的数据拿出来执行了
2.5 如果线程池满了会怎么办(线程池的拒绝策略)
拒绝抛出异常(默认策略)
静默拒绝:
给调用线程执行:占用资源
丢弃队列中最老的:
2.6 常见的工作队列有哪些
参考2.1
LinkedBlockingQueue 无界队列,容易OOM
SynchronousQueue : 缓存用,内部不存储数据
public SynchronousQueue(boolean fair) { // 直接new 了一个 transferqueue transferer = fair ? new TransferQueue<E>() : new TransferStack<E>(); }
TransferQueue() { QNode h = new QNode(null, false); // initialize to dummy node. head = h; tail = h; }
SynchronousQueue 也是一个队列来的,但它的特别之处在于它内部没有容器,一个生产线程,当它生产产品(即put的时候),如果当前没有人想要消费产品(即当前没有线程执行take),此生产线程必须阻塞,等待一个消费线程调用take操作,take操作将会唤醒该生产线程,同时消费线程会获取生产线程的产品(即数据传递),这样的一个过程称为一次配对过程(当然也可以先take后put,原理是一样的)。 ———————————————— 原文链接:https://blog.csdn.net/yanyan19880509/article/details/52562039
DelayedWorkQueue : 按照时间进行排序,由于定时调度
ArrayBlokingQueue: 指定大小
PriiriBlockingQueue: 优先级队列
LinkedTransferQueue:implements TransferQueue 预占模式
LinkedTransferQueue是ConcurrentLinkedQueue、SynchronousQueue(公平模式下转交元素)、LinkedBlockingQueue(阻塞Queue的基本方法)的超集 ———————————————— 原文链接:https://blog.csdn.net/qq_38293564/article/details/80593821
2.7 线程池抛出异常的方式
run方法中trycatch
重写 afterExecute()
线程工厂 ,uncaughtException
future.get 获取异常
2.8 一个线程池中的线程异常了,那么线程池会怎么处理这个线程?
源码可以参照1.5.5.1 execute源码部分
如果是execute,我们可以看到异常输出
如果是submit,我们是看不到异常的,可以调用Future.get()方法捕获异常
线程异常不会影响到线程池中其他线程的正常执行
线程池会把这个线程移除,并创建一个新的线程放到线程池中(因为异常后,会在workset中把这个worker删掉 workers.remove(w);,然后再新增一个非核心线程 addWorker(null, false))
2.9 线程池的几种状态
详见1.5.4
RUNNING/SHUTDOWN/STOP/TDIYING/TERMINATED
RUNNING 可以通过shutdown() 转为 SHUTDOWN
(RUNNING/SHUTDOWN) 可以通过shutdownnow() 转为 STOP
SHUTDOWN 状态下 如果队列中任务数为0 ,工作线程也为0 会转为 TDIYING
STOP状态下 如果工作线程数为0 转为 TDYING
TDYING 会通过 terminated() 转为 TERMINATED
2.10 线程的几种状态
详细可以参考下 我的另外一篇文章 https://blog.csdn.net/tiancaideshaonian/article/details/118886497
NEW: 线程刚刚创建
RUNABLE(READY/RUNNING)
WAITTING:等待唤醒
TIME_WAITTING:间隔时间后自动唤醒
BLOCKED:被阻塞,等待锁
TERMINATED: 进程结束