1. 线程的实现
三种方式
1. 使用内核线程实现
内核线程的定义:内核线程(Kernel-Level Thread简称KLT)是由操作系统内核支持的线程。线程的创建、销毁、调度都有内核完成。
一般程序是不会直接使用内核线程的,而是使用一种叫做轻量级进程(Light Weight Process简称LWT),这种东西就是我们上面通俗说的线程的概念。
每一个轻量级进程都由一个内核线程支持,它们是一一对应的关系。即线程创建、销毁、调度都是由内核线程完成的。
- 优点:线程的创建、销毁、调度都由内核来完成,简单。
- 缺点:线程的创建、销毁都要陷入内核态来完成,用户态和内核态的切换是很耗时的。
2. 使用用户线程实现
用户线程的意思是指线程的所有资源都由程序库实现,系统内核不感知用户线程的存在。
- 优点:线程的创建、销毁等操作都是在用户态实现的,所以效率很高。
- 缺点:线程的调度、线程的阻塞方式等等一系列的问题都要由程序库自己实现,太繁琐太复杂。一般由于硬件设施的不同,想要适配所有设施几乎不可能实现。
3. 使用内核线程和用户线程的混合实现
即同时存在内核线程和用户线程,在这种混合实现中,用户线程的创建、销毁等操作都还是在用户态完成,效率很高。而内核线程的调度等操作依旧由系统内核来完成。只需要维护一个关系:用户线程--内核线程的映射关系即可。
一般这种映射关系维持在多对多的情况下:
许多Unix系统比如Solaris/HP-UX都提供了这种线程模型
4. Java线程的选择
不同的操作系统支持不同的线程模型。
在Windows和Linux下,Java使用的是一对一的内核线程实现。
2. 线程的调度
调度一般分为两种:协调式调度和抢占式调度。
协调式
每个线程都会在执行完自己的所有指令后才会让出CPU。
- 缺点很明显,如果一个线程时间很长或者有问题,则它也不会让出CPU,导致整个系统阻塞。
抢占式
- 每个线程运行的时间有操作系统决定,线程本身无法决定。
这种方式很好解决了协调式的问题,不会因为某个线程有问题而导致整个系统阻塞。 - 抢占式还提供了线程的优先级设置,但这个不可信,只是一个参考。操作系统自己可以修改线程的优先级,所以即使设置线程的优先级,最后执行的时候也不一定真的有效。
2. 线程的状态
Java线程的状态有五种,即任一一个线程在一个时刻只会存在下面状态的一种。
- 新建(New)
创建后未启动的状态 - 运行(Running)
包括正在运行的和就绪的(即没有阻塞等待CPU分配时间)。 - 无限等待
这种状态的线程只能被其他线程唤醒,自己不会自己苏醒过来。 - 有限等待
这种状态的线程过了一段时间后,自己会自动苏醒过来。 - 阻塞
这种状态的线程因为某个互斥锁而被阻塞,当互斥锁被释放后,这种线程就会唤醒。 - 结束
已终止的线程。 - 总结一下
其实这里只是Java对线程的状态划分而已,没什么特别的。