深入理解java虚拟机笔记-java内存模式与线程4

4.2 Java线程调度

线程调度是指系统为线程分配处理器使用权的过程, 调度主要方式有两种, 分别是协同式 线程调度和抢占式线程调度。

如果使用协同式调度的多线程系统, 线程的执行时间由线程本身来控制, 线程把自己的工作执行完了之后, 要主动通知系统切换到另外一个线程上去。 协同式多线程的最大好处是实现简单, 而且由于线程要把自己的事情干完后才会进行线程切换, 切换操作对线程自己是可知的, 所以一般没有什么线程同步的问题。

Lua语言中的“协同例程”就是这类实现。 它的坏处也很明显: 线程执行时间不可控制, 甚至如果一个线程的代码编写有问题, 一直不告知系统进行线程切换, 那么程序就会一直阻塞在那里。 很久以前的Windows 3.x系统就是使用协同式来实现多进程多任务的, 那是相当不稳定的, 只要有一个进程坚持不让出处理器执行时间, 就可能会导致整个系统崩溃。

如果使用抢占式调度的多线程系统, 那么每个线程将由系统来分配执行时间, 线程的切换不由线程本身来决定。 譬如在Java中, 有Thread::yield()方法可以主动让出执行时间, 但是如果想要主动获取执行时间, 线程本身是没有什么办法的。

在这种实现线程调度的方式下, 线程的执行时间是系统可控的, 也不会有一个线程导致整个进程甚至整个系统阻塞的问题。

Java使用的线程调度方式就是抢占式调度。 与前面所说的Windows 3.x的例子相对, 在Windows 9x/NT内核中就是使用抢占式来实现多进程的, 当一个进程出了问题, 我们还可以使用任务管理器把这个进程杀掉, 而不至于导致系统崩溃。

虽然说Java线程调度是系统自动完成的, 但是我们仍然可以“建议”操作系统给某些线程多分配一点执行时间, 另外的一些线程则可以少分配一点——这项操作是通过设置线程优先级来完成的。

Java语言一共设置了10个级别的线程优先级(Thread.MIN_PRIORITY至Thread.MAX_PRIORITY) 。 在两个线程同时处于Ready状态时, 优先级越高的线程越容易被系统选择执行。

不过, 线程优先级并不是一项稳定的调节手段, 很显然因为主流虚拟机上的Java线程是被映射到系统的原生线程上来实现的, 所以线程调度最终还是由操作系统说了算。

 

4.3 状态转换

Java语言定义了6种线程状态, 在任意一个时间点中, 一个线程只能有且只有其中的一种状态, 并且可以通过特定的方法在不同状态之间转换。 这6种状态分别是:

1.新建(New) :

创建后尚未启动的线程处于这种状态。

2.运行(Runnable) :

包括操作系统线程状态中的Running和Ready, 也就是处于此状态的线程有可能正在执行, 也有可能正在等待着操作系统为它分配执行时间。

3.无限期等待(Waiting) :

处于这种状态的线程不会被分配处理器执行时间, 它们要等待被其他线程显式唤醒。 以下方法会让线程陷入无限期的等待状态:

3.1.没有设置Timeout参数的Object::wait()方法 3.2.没有设置Timeout参数的Thread::join()方法 3.3.LockSupport::park()方法。

4.限期等待(Timed Waiting) :

处于这种状态的线程也不会被分配处理器执行时间, 不过无须等待被其他线程显式唤醒, 在一定时间之后它们会由系统自动唤醒。 以下方法会让线程进入限期等待状态:

4.1.Thread::sleep()方法; 4.2.设置了Timeout参数的Object::wait()方法; 4.3.设置了Timeout参数的Thread::join()方法; 4.4.LockSupport::parkNanos()方法; 4.5.LockSupport::parkUntil()方法。

5.阻塞(Blocked) :

线程被阻塞了, “阻塞状态”与“等待状态”的区别是“阻塞状态”在等待着获取到一个排它锁, 这个事件将在另外一个线程放弃这个锁的时候发生; 而“等待状态”则是在等待一段时间, 或者唤醒动作的发生。 在程序等待进入同步区域的时候, 线程将进入这种状态。

6.结束(Terminated) :

已终止线程的线程状态, 线程已经结束执行。 上述6种状态在遇到特定事件发生的时候将会互相转换, 它们的转换关系如图12-6所示

 

posted @ 2022-03-22 15:10  Mars.wang  阅读(23)  评论(0编辑  收藏  举报