1. 创建线程的四种方式
- 继承Thread类
- 实现Runnable接口
- 实现Callable接口 + FutureTask (可以拿到返回结果,可以处理异常)
- 线程池
方式1和方式2: 主线程无法获取线程的运算结果。
方式3: 主进程可以获取线程的运算结果,但是不利于控制服务器中的线程资源。可能导致服务器资源耗尽。
用方式1、2和3创建线程,本质都是用new Thread()
。
在业务代码中,创建线程方式一律使用线程池的方式。
2. 创建线程池
2.1 Executors
public static final Integer THREAD_NUMBER = 10;
public static ExecutorService executorService = Executors.newFixedThreadPool(THREAD_NUMBER);
- Executors.newCachedThreadPool()
创建一个可缓存的线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。 - Executors.newFixedThreadPool()
创建一个定长的线程池,可控制线程最大并发数,超出的线程会在队列里等待。 - Executors.newSingleThreadExecutor()
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务都能够顺序执行。 - Executors.newScheduledThreadPool()
创建一个定长线程池,支持定时及周期性的任务执行 - Executors.newWorkStealingPool()
切记不要在服务调用层面创建线程池。
2.2 new ThreadPoolExecutor()
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler){
...
}
参数说明:
corePoolSize:the number of threads to keep in the pool, even if they are idle, unless {@code allowCoreThreadTimeOut} is set.
核心线程数:线程池创建好后准备就绪的线程,这些数量的线程会一直存在于线程池,即使它们没有被使用,除非allowCoreThreadTimeOut被设置。
maximumPoolSize: the maximum number of threads to allow in the pool.
最大线程数:该线程池允许的最大线程数。
keepAliveTime: when the number of threads is greater than the core, this is the maximum time that excess idle threads will wait for new tasks before terminating.
存活时间:当线程池中的线程数量大于核心线程数时,多出来的线程销毁的最大等待时间。
unit:the time unit for the {@code keepAliveTime} argument.
时间单位:keepAliveTime 的时间单位。
BlockingQueue workQueue:the queue to use for holding tasks before they are executed. This queue will hold only the {@code Runnable} tasks submitted by the {@code execute} method.
阻塞队列:如果任务有很多,就会将目前多出来的未被执行的任务放在这个队列里。只要有线程空闲了,就会去这个队列里取出新的任务。
threadFactory:the factory to use when the executor creates a new thread.
线程工厂:出现新线程的工厂。
handler:the handler to use when execution is blocked because the thread bounds and queue capacities are reached.
处理器:阻塞队列被塞满了,按照这个处理编写的拒绝处理方式执行。
处理器类型:
AbortPolicy: 新进入的线程会被抛弃,然后抛出异常。
DiscardOldestPolicy: 丢弃未被执行的最老的线程。
DiscardPolicy: 丢弃当前正在执行的线程,不抛出异常。
CallerRunsPolicy: 在任务被拒绝添加后,会在调用execute方法的的线程来执行被拒绝的任务。
3. 线程池的工作顺序
- 线程池被创建,核心线程准备就绪
- 当新的线程进入时,核心线程会执行
- 当核心线程都会占用时,新进入的线程会直接进入到阻塞队列中
- 当新的线程陆续进入,且核心线程被占用。阻塞队列被塞满,这时,线程池会创建新的线程去执行,新创建的线程数与核心线程数的总数不超过最大线程数
- 当新的线程仍然持续进入,阻塞队列被塞满,最大数量的线程也都被占用,这个时候会启动处理器,根据处理器定义的新线程处理规格处理新进入的线程
- 当所有的线程都执行完后,最大线程数-核心线程数的线程会在最大存活时间后自动被释放