线程
进程、线程,经常傻傻分不清楚。
进程,是一个动态的过程,是一个活动的实体。简单来说,一个应用程序的运行就可以被看做是一个进程。
而线程,是运行中的实际的任务执行者,它是程序执行流的最小执行单位。
可以说,进程中包含了多个同时运行的线程。
关于进程和线程,可以查看阮一峰的这篇文章,浅显易懂。
线程的生命周期
new Thread()
创建一个新线程,在线程创建完成后,线程就进入了就绪(Runnable)状态,并开始抢占CPU资源。
当线程抢到了CPU执行权,线程就进入了运行(Running)状态。
当线程的任务执行完成或者调用stop()
后,线程就进入了死亡状态。
线程也可能进入阻塞状态,比如,
- 当线程主动调用
sleep()
时,线程会进入阻塞状态。而当sleep()
的睡眠时长过去之后,线程会自动跳出阻塞状态。 - 当线程主动调用阻塞时的IO方法时,这个方法有个返回参数,在该参数返回之前,线程会进入阻塞状态。参数返回之后,线程会自动跳出阻塞状态。
- 当线程正在等待某个通知时,会进入阻塞状态。当线程获取到了通知后,就会自动跳出阻塞过程。
生命周期函数
start()
run()
stop()
sleep()
wait()
单线程与多线程
单线程,只有一个线程在执行任务。
多线程,有多个线程同时在执行任务。
线程池的创建
Java提供了创建线程池的接口类Executor
。
public interface Executor {
/**
* Executes the given command at some time in the future. The command
* may execute in a new thread, in a pooled thread, or in the calling
* thread, at the discretion of the {@code Executor} implementation.
*
* @param command the runnable task
* @throws RejectedExecutionException if this task cannot be
* accepted for execution
* @throws NullPointerException if command is null
*/
void execute(Runnable command);
}
通常我们会实现Executor
的实现类ThreadPoolExecutor
来创建线程池。
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
- corePoolSize,线程池中的核心线程数量。
- maximumPoolSize,线程池中可以容纳的最大线程数量。
- keepAliveTime,非核心线程在空闲时间里最大的存活时间。线程池中的核心线程,即使在无任务的情况下也不能被清除,其他的线程则是有存活时间的。
- workQueue,等待队列,任务可以存储在任务队列中等待被执行。
线程池的执行
当有任务进来时,判断核心线程是否处于空闲状态,如果不是空闲状态,则核心线程先执行任务;
如果核心线程已满,则判断任务队列是否有空间存放该任务,如果有,则将该任务保存在任务队列中,等待执行;
如果任务队列已满,则判断线程池最大可容纳的线程数,如果没有超出这个数,就创建非核心线程执行任务;
如果超出了这个数,则调用handler实现拒绝策略。
handler的拒绝策略有四种,分别是,
- AbortPolicy。不执行新任务,直接抛出异常。
- DiscardPolicy。不执行新任务,也不抛出异常。
- DiscardOldestPolicy。抛弃线程池中最后要执行的任务,并执行新传进来的任务。
- CallerRunsPolicy。直接调用execute来执行当前任务。
常见的线程池
- CachedThreadPool
可缓存的线程池,该线程池中没有核心线程,有非核心线程,非核心线程的数量为Integer.MAX_VALUE
,即无限大。当有需要时,创建线程来执行任务;当没有需要时,则回收线程。使用于耗时少、任务量大的情况。 - ScheduleThreadPool
周期性执行任务的线程池。按照某种特定的计划执行线程中的任务,有核心线程,也有非核心线程,非核心线程的数量为无限大。适用于执行周期性任务的情况。 - SingleThreadPool
只有一条线程来执行任务,适用于有顺序的任务的应用场景。 - FixedThreadPool
定长的线程池,有核心线程,核心线程的数量为最大的线程数量,没有非核心线程。