一、什么是线程?为什么需要线程池?
什么是线程?
线程是程序中执行的线程。 Java虚拟机允许应用程序具有多个并发运行的执行线程。
每个线程都有一个优先级。 优先级高的线程优先于优先级低的线程执行。 每个线程可能被标记为守护进程,也可能不被标记为守护进程。 当在某个线程中运行的代码创建一个新的thread对象时,新线程的优先级最初被设置为与创建线程的优先级相等,并且当且仅当创建线程是守护线程时,它(新线程)才是守护线程。
当Java虚拟机启动时,通常有一个非守护线程(它通常调用某个指定类的名为main的方法)。 Java虚拟机继续执行线程,直到发生以下任何一种情况:
- 类Runtime的退出方法已被调用,安全管理器已允许执行退出操作。
- 所有不是守护线程的线程都已经死亡,要么从对run方法的调用返回,要么抛出一个传播到run方法之外的异常。
以上摘自jdk1.8 Thread类官方注释:
为什么需要线程池?
概念
线程池(Thread Pool)是一种线程使用模式,线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。java.util.concurrent.Executors
提供了一个java.util.concurrent.Executor
接口的实现用于创建线程池。
优点
- 降低系统资源消耗,通过重用已存在的线程,降低线程创建和销毁造成的消耗;
- 提高系统响应速度,当有任务到达时,通过复用已存在的线程,无需等待新线程的创建便能立即执行;
- 方便线程并发数的管控。因为线程若是无限制的创建,可能会导致内存占用过多而产生OOM,并且会造成cpu过度切换。
ps:cpu切换线程是有时间成本的(需要保持当前执行线程的现场,并恢复要执行线程的现场)。
二、当新任务进来时,线程池如何工作?
三、如何创建一个线程池?
创建线程池的构造函数
通过java.util.concurrent.ThreadPoolExecutor
来进行自定义线程池,这里不建议用模板线程池,建议通过自定义的方式(具体场景具体分析)来创建线程池。
参数设置
- corePoolSize
当线程池被创建后,线程池中就会有指定数量的线程被创建用来等待任务的执行,这些线程被称为核心线程。即使它们是空闲的,它们也不会被销毁。除非设置了allowCoreThreadTimeOut参数。
- maximumPoolSize
线程池所能容纳的最大线程数量。
- keepAliveTime
用来指定非核心线程被创建后最多可以存活的时间。
- unit
用来设置上述时间的单位。
- workQueue
用来保存等待执行的任务。
- threadFactory(非必填参数,若不填写则使用默认值)
执行程序创建新线程时使用的工厂
- handler(非必填参数,若不填写则使用默认值)
拒绝策略
四、线程池的workQueue有哪些?
1. SynchronousQueue
SynchronousQueue没有容量,是无缓冲等待队列,是一个不存储元素的阻塞队列,会直接将任务交给消费者,必须等队列中的添加元素被消费后才能继续添加新的元素。
2. LinkedBlockingQueue
LinkedBlockingQueue是一个无界缓存等待队列。当前执行的线程数量达到corePoolSize的数量时,剩余的元素会在阻塞队列里等待。
3. ArrayBlockingQueue
ArrayBlockingQueue是一个有界缓存等待队列,可以指定缓存队列的大小,当正在执行的线程数等于corePoolSize时,多余的元素缓存在ArrayBlockingQueue队列中等待有空闲的线程时继续执行,当ArrayBlockingQueue已满时,加入ArrayBlockingQueue失败,会开启新的线程去执行,当线程数已经达到最大的maximumPoolSizes时,再有新的元素尝试加入ArrayBlockingQueue时会执行拒绝策略。
五、线程池的拒绝策略有哪些?
1. AbortPolicy
丢弃任务并抛出RejectedExecutionException异常。
/**
* A handler for rejected tasks that throws a
* {@code RejectedExecutionException}.
*/
public static class AbortPolicy implements RejectedExecutionHandler {
/**
* Creates an {@code AbortPolicy}.
*/
public AbortPolicy() { }
/**
* Always throws RejectedExecutionException.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
* @throws RejectedExecutionException always
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
2. DiscardPolicy
丢弃任务,但是不抛出异常。
/**
* A handler for rejected tasks that silently discards the
* rejected task.
*/
public static class DiscardPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code DiscardPolicy}.
*/
public DiscardPolicy() { }
/**
* Does nothing, which has the effect of discarding task r.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}
3. DiscardOldestPolicy
丢弃队列最前面的任务,然后重新提交被拒绝的任务
/**
* A handler for rejected tasks that discards the oldest unhandled
* request and then retries {@code execute}, unless the executor
* is shut down, in which case the task is discarded.
*/
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code DiscardOldestPolicy} for the given executor.
*/
public DiscardOldestPolicy() { }
/**
* Obtains and ignores the next task that the executor
* would otherwise execute, if one is immediately available,
* and then retries execution of task r, unless the executor
* is shut down, in which case task r is instead discarded.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
}
4. CallerRunsPolicy
由调用线程(提交任务的线程)处理该任务
/**
* A handler for rejected tasks that runs the rejected task
* directly in the calling thread of the {@code execute} method,
* unless the executor has been shut down, in which case the task
* is discarded.
*/
public static class CallerRunsPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code CallerRunsPolicy}.
*/
public CallerRunsPolicy() { }
/**
* Executes task r in the caller's thread, unless the executor
* has been shut down, in which case the task is discarded.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}