线程
一、什么是线程
操作系统能够进行运算调度的最小单位。线程分为用户线程内核线程,内核线程与用户线程存在状态切换。用户态内核态上下文切换比较耗时。
二、线程状态
二、线程模型
线程模型分为三种
- 多对一线程模型(N:1)
- 一对一线程模型(1:1)
- 多对多线程模型(N:N)
-
多对一线程模型(N:1)
多个用户线程映射到一个内核线程,用户线程建立在用户空间的线程库上,用户线程的建立、同步、销毁和调度完全在用户态中完成,对内核透明
优点:
- 线程的上下文切换都发生在用户空间,避免了模态切换(mode switch),减少了性能的开销。
- 用户线程的创建不受内核资源的限制,可以支持更大规模的线程数量。
缺点
- 所有的线程基于一个内核调度实体即内核线程,这意味着只有一个处理器可以被利用,浪费了其它处理器资源,不支持并行,在多处理器环境下这是不能够被接受的,如果线程因为 I/O 操作陷入了内核态,内核态线程阻塞等待 I/O 数据,则所有的线程都将会被阻塞。
- 增加了复杂度,所有的线程操作都需要用户程序自己处理,而且在用户空间要想自己实现 “阻塞的时候把线程映射到其他处理器上” 异常困难
-
一对一线程模型(1:1) — JVM 使用的线程模型
每个用户线程都映射到一个内核线程,每个线程都成为一个独立的调度单元,由内核调度器独立调度,一个线程的阻塞不会影响到其他线程,从而保障整个进程继续工作
优点:
- 每个线程自成独立调度单元,使用内核提供的线程调度功能及处理器映射,可以完成线程的切换,并将线程的任务映射到其他处理器上,充分利用多核处理器的优势,实现真正的并行
缺点:
- 没创建一个用户级线程都需要创建一个内核线程雨其对应,因此需要消耗一定程度的内核资源,而内核资源是有限的,所以创建的线程数量也是有限的
- 需要频繁进行用户态与内核态切换,开销比较大
-
多对多线程模型(N:N)
内核线程和用户线程的数量比为 M : N,这种模型需要内核线程调度器和用户空间线程调度器相互操作,本质上是多个线程被映射到了多个内核线程。
优点:
- 用户线程的创建、切换、析构及同步依然发生在用户空间,能创建数量更多的线程,支持更大规模的并发
- 大部分的线程上下文切换都发生在用户空间,减少了模态切换带来的开销
- 可以使用内核提供的线程调度功能及处理器映射,充分利用多核处理器的优势,实现真正的并行,并降低了整个进程被完全阻塞的风险。
三、线程池
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
- corePoolSize-核心线程数(包括空闲线程),需要注意的是在初创建线程池时线程不会立即启动,直到有任务提交才开始启动线程并逐渐时线程数目达到corePoolSize。若想一开始就创建所有核心线程需调用prestartAllCoreThreads方法
- maximumPoolSize-最大线程数
- keepAliveTime - (corePoolSize,maximumPoolSize) 空闲线程,超过改时间 回收这部分线程
- unit - keepAliveTime 单位(NANOSECONDS、MICROSECONDS、MILLISECONDS、SECONDS、MINUTES、DAYS)
- workQueue - 当线程数目超过核心线程数时用于保存任务的队列。主要有3种类型的BlockingQueue可供选择:无界队列,有界队列和同步移交。将在下文中详细阐述
- ArrayBlockingQueue - FIFO 队列
- LinkedBlockingQueue - 无界队列
- PriorityBlockingQueue - 指定优先级队列
- threadFactory - 执行新建线程的工厂
- handler - 拒绝策略
- AbortPolicy - 中止策略
- DiscardPolicy - 抛弃策略
- DiscardOldestPolicy - 抛弃旧任务策略,先将阻塞队列中的头元素出队抛弃,再尝试提交任务。如果此时阻塞队列使用PriorityBlockingQueue优先级队列,将会导致优先级最高的任务被抛弃,因此不建议将该种策略配合优先级队列使用
- CallerRunsPolicy - 调用者运行
创建线程时机:
线程数< corePoolSize ,
submit task 时会创建一个线程
线程数 = corePoolSize,
队列满时 submit task 创建线程