JVM相关及其拓展(六) -- Java与线程
Java与线程
线程的实现
线程是比进程更轻量级的调度执行单位,线程的引入可以把一个进程的资源分配和执行调度分开,各个线程间既可以共享进程资源,又可以独立调度(线程是CPU调度的基本单位
)。
实现线程主要有三种方式:
使用内核线程实现
直接由操作系统内核支持的线程。
由内核来完成切换,内核通过操纵调度器对线程进行调度,并负责将线程的任务映射到各个处理器上。
多线程内核
:有能力处理多件事情,支持多线程的内核轻量级进程
:内核线程的一种高级接口。只有先支持内核线程,才能有轻量级进程
- 优点:每个轻量级进程都是一个独立的调度单元,即使有一个在系统调用中堵塞了,也不影响整个进程继续工作。
- 缺点:各种线程操作都需要进行系统调用,代价相对高,需要在用户态和内核态中来回切换。另外轻量级进程的数量是有限的。
- 轻量级进程与内核线程是1:1的关系
使用用户线程实现
广义:一个线程只要不是内核线程,就可以认为是用户线程
狭义:完全建立在用户空间的线程库上,而系统内核不能感知线程存在的实现
- 优点:线程的建立、同步、销毁和调度都在用户态中完成,不需要内核参与,所以操作时非常快速且低消耗,还支持更大的线程数量
- 缺点:没有系统内核的支持,所有线程操作都需要用户程序自己处理,实现较复杂
- 进程与用户线程之间是1:N的关系
使用用户线程加轻量级进程混合实现
既存在用户线程,也存在轻量级进程。
- 优点:用户线程还是在用户空间中,还可以支持大规模的用户线程并发;轻量级进程可以作为内核线程和用户线程之间的桥梁,用户线程的系统调用需要轻量级进程来完成,大大降低了系统被阻塞的危险。
- 采用多对多的线程模型。
Java线程的实现是不能确定的。由于操作系统支持怎样的线程模型,在很大程度上决定了Java虚拟机的线程是怎样映射的。
线程调度
系统为线程分配处理器使用权的过程。
主要调度方式有两种:
协同式线程调度
线程的执行时间有 线程本身 控制,线程把自己的工作执行完后,要主动通知系统切换到另一个线程上。
- 优点:实现简单,切换操作可知,基本不存在线程同步问题
- 缺点:线程执行时间不可控
抢占式线程调度
每个线程由系统分配执行时间,线程的切换不由线程本身决定
线程执行时间是可控的,不存在因为一个线程而堵塞整个系统的问题
可以设置线程优先级,优先级越高的线程越容易被系统选择执行
线程优先级并不是太靠谱,一方面线程调度还是取决于操作系统,优先级的实现不会太一致。另一方面优先级会被系统自行改变。
线程状态转换
在任意时间点,一个线程有且只有一个状态
新建
线程创建后尚未启动的线程状态
运行
包括正在执行和等待着CPU为它分配执行时间
无限期等待
不会被分配CPU执行时间,要等待被其他线程显示的唤醒。以下方法会让线程陷入无限期的等待状态:
- 没有设置Timeout参数的
Object,wait()
- 没有设置Timeout参数的
Thread.join()
LockSupport.park()
- 没有设置Timeout参数的
限期等待
不会被分配CPU执行时间,但在一定时间后会被系统唤醒。以下方法会让线程进入限期等待状态:
Thread.sleep()
- 设置Timeout参数的
Object,wait()
- 设置Timeout参数的
Thread.join()
LockSupport.parkNanos()
LockSupport.parkUntil()
阻塞
线程被阻塞了 在程序等待进入同步区域的时候进入这种状态。
阻塞状态:等待着获取到一个排他锁,将在另一个线程放弃这个锁的时候发生
等待状态:在等待一段时间或者唤醒动作的发生
结束
线程已经结束执行
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!