Java线程的上下文切换与线程状态
Posted 张维鹏
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java线程的上下文切换与线程状态相关的知识,希望对你有一定的参考价值。
一、上下文切换:
在并发编程中,并不是线程越多就效率越高,线程数太少可能导致资源不能充分利用,线程数太多可能导致竞争资源激烈,然后上下文切换频繁造成系统的额外开销。那什么是上下文切换呢?
1、什么是上下文切换:
在处理多线程并发任务时,处理器会给每个线程分配CPU时间片,线程在各自分配的时间片内占用处理器并执行任务,当线程的时间片用完了,或者自身原因被迫暂停运行的时候,就会有另外一个线程来占用这个处理器,这种一个线程让出处理器使用权,另外一个线程获取处理器使用权的过程就叫做上下文切换。
一个线程让出CPU处理器使用权,就是“切出”;另外一个线程获取CPU处理器使用权。就是“切入”,在这个切入切出的过程中,操作系统会保存和恢复相关的进度信息,而这个进度信息就是我们常说的“上下文”,上下文一般包含了寄存器的存储内容以及程序计数器存储的指令内容。
对于单核单线程 CPU 而言,在某一时刻只能执行一条 CPU 指令。从用户角度看,计算机能够并行运行多个进程,这恰恰是操作系统通过快速上下文切换造成的结果。每个时间片的大小一般为几十毫秒,所以在一秒钟就可能发生几十上百次的线程相互切换,给我们的感觉就是同时进行的
2、Java 多线程的上下文切换:
在 Java 中,多线程的上下文切换就是多线程两个运行状态的相互切换导致的。在切换时操作系统保存的上下文信息,当线程从 BLOCKED 状态进入到 RUNNABLE 时,也就是线程的唤醒,此时线程将获取上次保存的上下文信息,接着之前的进度继续执行。
在 Java 中,两种情况会导致上下文切换:一种是自发性上下文切换,也就是程序本身触发的切换;另一种是非自发性上下文切换,也就是系统或者虚拟机导致的上下文切换。
(1)自发性上下文是线程由 Java 程序调用导致切出,一般是在编码的时候,调用以下几个方法或关键字:
sleep()、wait()、yield()、join()、park()、synchronized、lock
(2)非自发的上下文切换常见的有:线程被分配的时间片用完,虚拟机垃圾回收导致,或者执行优先级的问题导致
3、上下文切换的系统开销:
- 操作系统保存和恢复上下文
- 处理器高速缓存加载
- 调度器进行调度
- 上下文切换可能导致的高速缓冲区被冲刷
4、小结:
上下文切换就是一个线程释放处理器的使用权,另外一个线程获取处理器的使用权的过程;在切入切出时,系统会保存和读取当前线程的上下文信息,用户恢复线程的执行进度;自发和非自发的调用操作,都会导致上下文切换,会导致系统资源开销。
线程越多不一定执行的速度越快,在单个逻辑比较简单的时候,而且速度相对来说非常快的情况下,我们推荐是使用单线程。如果逻辑非常复杂,或者需要进行大量的计算的地方,我们建议使用多线程来提高系统的性能。
二、Java 线程的状态:
1、线程状态说明:
在 JDK 的 java.lang.Thread.State 源码中定义了6个状态,在某一时刻,一个线程只能处于一种状态:
- New:新创建且尚未启动的线程状态。
- Runnable:可运行状态,已获得除CPU以外的所需的一切资源,等待CPU调度。
- Blocked:阻塞状态,线程阻塞等待监视器锁定,处于 synchronized 同步代码块或方法中被阻塞。
- Waiting:等待状态。下列不带超时的方式:Object.wait()、Thread.join()、 LockSupport.park()
- Timed Waiting:超时等待状态,指定了等待时间的线程状态。下列带超时的方式:Thread.sleep()、0bject.wait()、 Thread.join()、 LockSupport.parkNanos()、 LockSupport.parkUntil()
- Terminated:线程终止状态,线程正常完成执行或出现异常
(1)New:实现 Runnable 接口和继承 Thread 类可以得到一个线程类,当线程实例被 new 创建后,就进入了 NEW 状态,但是此时线程还没有开始执行,
(2)RUNNABLE:标识线程已经准备就绪,等待CPU调度,此时还是还没真正执行。转换成该状态的条件:
-
① 当调用线程的 start() 方法时,线程也不一定会马上执行,因为 Java 线程是映射到操作系统的线程执行的,还需要等CPU调度,但此时该线程的状态已经为 RUNNABLE
-
② 当前线程时间片用完
-
③ Thread.yield():当前线程调用 yield() 方法,放弃所获取的 CPU 时间片,由运行状态变会可运行状态,让同优先级的线程执行,但不保证一定能达到让步的目的,因为让步的线程有可能被线程调度程序再次选中。
-
④ join() 的线程结束:在当前线程里调用线程A的 join() 方法,当前线程阻塞但不释放对象锁,直到线程A执行完毕 或者 millis 时间到,当前线程进入可运行状态。
-
⑤ Thread.sleep(long millis):当前线程调用 sleep() 方法,当前线程进入阻塞但不释放对象锁,millis 后线程自动苏醒进入可运行态。
-
⑥ 锁池里的线程拿到对象锁后,进入可运行状态
(3)WAIT 等待:等待状态,处于等待状态的线程正在等待另一个线程执行特定操作。例如:
- Object.wait():一个在对象上调用 Object.wait() 的线程正在等待另一个线程在该对象上调用 Object.notify() 或 Object.notifyAll(),这样便可以控制线程的执行顺序。
- Thread.join():线程正在等待指定的 join 线程终止
- LockSupport.park()
2、java.lang.Thread.State 源码:
public enum State
/**
* Thread state for a thread which has not yet started.
*/
NEW,
/**
* Thread state for a runnable thread. A thread in the runnable
* state is executing in the Java virtual machine but it may
* be waiting for other resources from the operating system
* such as processor.
*/
RUNNABLE,
/**
* Thread state for a thread blocked waiting for a monitor lock.
* A thread in the blocked state is waiting for a monitor lock
* to enter a synchronized block/method or
* reenter a synchronized block/method after calling
* @link Object#wait() Object.wait.
*/
BLOCKED,
/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* following methods:
* <ul>
* <li>@link Object#wait() Object.wait with no timeout</li>
* <li>@link #join() Thread.join with no timeout</li>
* <li>@link LockSupport#park() LockSupport.park</li>
* </ul>
*
* <p>A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called <tt>Object.wait()</tt>
* on an object is waiting for another thread to call
* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
* that object. A thread that has called <tt>Thread.join()</tt>
* is waiting for a specified thread to terminate.
*/
WAITING,
/**
* Thread state for a waiting thread with a specified waiting time.
* A thread is in the timed waiting state due to calling one of
* the following methods with a specified positive waiting time:
* <ul>
* <li>@link #sleep Thread.sleep</li>
* <li>@link Object#wait(long) Object.wait with timeout</li>
* <li>@link #join(long) Thread.join with timeout</li>
* <li>@link LockSupport#parkNanos LockSupport.parkNanos</li>
* <li>@link LockSupport#parkUntil LockSupport.parkUntil</li>
* </ul>
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
TERMINATED;
参考文章:
以上是关于Java线程的上下文切换与线程状态的主要内容,如果未能解决你的问题,请参考以下文章
Java多线程 -- 线程的生命周期和状态什么是上下文切换线程死锁避免死锁 sleep() 方法和 wait() 方法的区别和共同点为什么调用 start() 方法会执行 run() 方法