线程流转状态图

  |   0 评论   |   1,514 浏览

20181103195207299.jpg

  1. 新建状态(New): 线程对象被创建后,就进入了新建状态。例如,Thread thread = new Thread()。
  2. 就绪状态(Runnable): 也被称为“可执行状态”。线程对象被创建后,其它线程调用了该对象的start()方法,从而来启动该线程。例如,thread.start()。处于就绪状态的线程,随时可能被CPU调度执行。
  3. 运行状态(Running) : 线程获取CPU权限进行执行。需要注意的是,线程只能从就绪状态进入到运行状态。
  4. 阻塞状态(Blocked) : 阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
    (01) 等待阻塞(左下角Blocket) -- 通过调用线程的wait()方法,让线程等待某工作的完成。该方法会释放锁进入等待池。当他唤醒后就进入锁池等待获得锁,获得锁后继续完成wait()方法后面的代码,才能进入到就绪状态。
    (02) 同步阻塞 (右下角Blocket)-- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态(进入锁池)。
    (03) 其他阻塞(最上面的Blocket) -- 通过调用线程的sleep()(sleep不会释放锁)或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
  5. 死亡(dead) :线程 run ()、 main () 方法执行结束,或者因异常退出了 run ()方法,则该线程结束生命周期。死亡的线程不可再次复生。

yield相关

我们知道 start() 方法是启动线程,让线程变成就绪状态等待 CPU 调度后执行。

那 yield() 方法是干什么用的呢?来看下源码。

* its current use of a processor. The scheduler is free to ignore this
 * hint.
 *
 * <p> Yield is a heuristic attempt to improve relative progression
 * between threads that would otherwise over-utilise a CPU. Its use
 * should be combined with detailed profiling and benchmarking to
 * ensure that it actually has the desired effect.
 *
 * <p> It is rarely appropriate to use this method. It may be useful
 * for debugging or testing purposes, where it may help to reproduce
 * bugs due to race conditions. It may also be useful when designing
 * concurrency control constructs such as the ones in the
 * {@link java.util.concurrent.locks} package.
 */
public static native void yield();
1234567891011121314151617

yield 即 “谦让”,也是 Thread 类的方法。它让掉当前线程 CPU 的时间片,使正在运行中的线程重新变成就绪状态,并重新竞争 CPU 的调度权。它可能会获取到,也有可能被其他线程获取到。

实战

下面是一个使用示例。

public static void main(String[] args) {
	Runnable runnable = () -> {
		for (int i = 0; i <= 100; i++) {
			System.out.println(Thread.currentThread().getName() + "-----" + i);
			if (i % 20 == 0) {
				Thread.yield();
			}
		}
	};
	new Thread(runnable, "栈长").start();
    new Thread(runnable, "小蜜").start();
}
123456789101112131415

这个示例每当执行完 20 个之后就让出 CPU,每次谦让后就会马上获取到调度权继续执行。

运行以上程序,可以有以下两种结果。

结果1:栈长让出了 CPU 资源,小蜜成功上位。

栈长-----29
栈长-----30
小蜜-----26
栈长-----31
1234

结果2:栈长让出了 CPU 资源,栈长继续运行。

栈长-----28
栈长-----29
栈长-----30
栈长-----31
1234

而如果我们把两个线程加上线程优先级,那输出的结果又不一样。

thread1.setPriority(Thread.MIN_PRIORITY);
thread2.setPriority(Thread.MAX_PRIORITY);
12

因为给小蜜加了最高优先权,栈长加了最低优先权,即使栈长先启动,那小蜜还是有很大的概率比栈长先会输出完的,大家可以试一下。

yield 和 sleep 的异同

  1. yield, sleep 都能暂停当前线程,sleep 可以指定具体休眠的时间,而 yield 则依赖 CPU 的时间片划分。
  2. yield, sleep 两个在暂停过程中,如已经持有锁,则都不会释放锁资源。
  3. yield 不能被中断,而 sleep 则可以接受中断。

如果一定要用它的话,一句话解释就是:yield 方法可以很好的控制多线程,如执行某项复杂的任务时,如果担心占用资源过多,可以在完成某个重要的工作后使用 yield 方法让掉当前 CPU 的调度权,等下次获取到再继续执行,这样不但能完成自己的重要工作,也能给其他线程一些运行的机会,避免一个线程长时间占有 CPU 资源。


标题:线程流转状态图
作者:jackssybin
地址:https://jackssybin.cn/articles/2020/10/22/1603355147679.html

评论

发表评论


取消