线程是什么,线程和进程的区别是什么
线程,程序执行流的最小执行单位。是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
线程的生命周期
单线程和多线程
单线程:只有一条线程在执行任务;
多线程:创建多条线程同时执行任务。
并行和并发
- 并行
同一时间段内多个任务一起执行,由于CPU的运算速度非常快,任务的交替执行在我们看来是同时执行。 - 并发
真正意义上的同时执行多个任务,通过多核CPU,多个任务可在同一时刻一起执行。
多线程的安全问题
多个线程同时执行一个任务时,它们会共享同一份资源,由于线程CPU的资源可能被任何一个线程抢占,当第一条线程先抢占到CPU资源,它进行了一个操作,此时第二条线程抢占到了CPU资源,而共享资源还来不及变化,就有两条线程中的数据使用了同一资源,具体可参考多线程买票问题。这个问题应该如何解决呢?
这个问题主要的矛盾在于,CPU的使用权抢占和资源的共享发生了冲突,解决时,我们只需要让一条线程抢占了CPU资源时,阻止第二条线程抢占CPU的执行权,在代码中,只需要在方法中使用同步代码块即可。
详细参考:https://blog.csdn.net/weimeig/article/details/79512965
线程池
在一个应用程序中,我们可能需要多次创建并销毁线程,而创建并销毁线程的过程势必会消耗内存。在Java中,内存资源是极其宝贵的,所以,我们提出了线程池的概念。
线程池:
Java中开辟出了一种管理线程的概念,这个概念叫做线程池。从概念及应用场景可看出,线程池的好处就是可以方便的管理线程,并减少内存的消耗。
Java中提供了创建线程池的一个类:Executor,而我们创建时,一般使用其子类:ThreadPoolExecutor
ThreadPoolExecutor
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
这是其中最重要的一个构造方法,它决定了创建出来的线程池的各种属性,用两张图来直观地理解线程池和这几个参数:
corePoolSize,maximumPoolSize,workQueue之间的关系:
- 当线程池中线程数小于corePoolSize时,新提交任务将创建一个新线程执行任务,即使此时线程池中存在空闲线程。
- 当线程池中线程数达到corePoolSize时,新提交任务将被放入workQueue中,等待线程池中任务调度执行 。
- 当workQueue已满,且maximumPoolSize > corePoolSize时,新提交任务会创建新线程执行任务。
- 当workQueue已满,且提交任务数超过maximumPoolSize,任务由RejectedExecutionHandler处理。
- 当线程池中线程数超过corePoolSize,且超过这部分的空闲时间达到keepAliveTime时,回收这些线程。
- 当设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize范围内的线程空闲时间达到keepAliveTime也将回收。
线程池的执行流程
任务进来时,首先执行判断,判断核心线程是否处于空闲状态,如果不是,核心线程就先就执行任务,如果核心线程已满,则判断任务队列是否有地方存放该任务,若果有,就将任务保存在任务队列中,等待执行,如果满了,在判断最大可容纳的线程数,如果没有超出这个数量,就开创非核心线程执行任务,如果超出了,就调用handler实现拒绝策略。
handler的拒绝策略
四种:
- AbortPolicy:不执行新任务,直接抛出异常,提示线程池已满;
- DisCardPolicy:不执行新任务,也不抛出异常;
- DisCardOldSetPolicy:将消息队列中的第一个任务替换为当前新进来的任务执行;
- CallerRunsPolicy:直接调用execute来执行当前任务
常见的线程池
- CachedThreadPool
可缓存的线程池,该线程池中没有核心线程,非核心线程的数量为Integer.max_value,就是无限大,当有需要时创建线程来执行任务,没有需要时回收线程,适用于耗时少,任务量大的情况。 - SecudleThreadPool
周期性执行任务的线程池,按照某种特定的计划执行线程中的任务,有核心线程,但也有非核心线程,非核心线程的大小也为无限大。适用于执行周期性的任务。 - SingleThreadPool
只有一条线程来执行任务,适用于有顺序的任务的应用场景。 - FixedThreadPool
定长的线程池,有核心线程,核心线程的即为最大的线程数量,没有非核心线程。