1、sleep 与 yield
sleep
-
调用 sleep 会让当前线程从 Running 进入 Timed Waiting 状态(阻塞)
-
其它线程可以使用 interrupt 方法打断正在睡眠的线程,这时 sleep 方法会抛出
InterruptedException
-
睡眠结束后的线程未必会立刻得到执行
-
建议用 TimeUnit 的 sleep 代替 Thread 的 sleep 来获得更好的可读性(TimeUnit.SECONDS.sleep(1);)
调用sleep
public static void main(String[] args) {Thread t1 = new Thread("t1") {@Overridepublic void run() {try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}}};
t1.start();log.debug("t1 state: {}", t1.getState());
try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}log.debug("t1 state: {}", t1.getState());}
输出
22:23:02.365 c.Test6 [main] - t1 state: RUNNABLE
22:23:02.893 c.Test6 [main] - t1 state: TIMED_WAITING
调用interrupt
public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread("t1") {@Overridepublic void run() {log.debug("enter sleep...");try {Thread.sleep(2000);} catch (InterruptedException e) {log.debug("wake up...");e.printStackTrace();}}};t1.start();
Thread.sleep(1000);log.debug("interrupt...");t1.interrupt();}
输出
22:26:48.155 c.Test7 [t1] - enter sleep...
22:26:49.158 c.Test7 [main] - interrupt...
22:26:49.158 c.Test7 [t1] - wake up...
java.lang.InterruptedException: sleep interruptedat java.lang.Thread.sleep(Native Method)at cn.itcast.test.Test7$1.run(Test7.java:14)
yield
-
调用 yield 会让当前线程从 Running 进入 Runnable 就绪状态,然后调度执行其它线程,注意:如果没有其他线程的话,可能还是执行当前线程
-
具体的实现依赖于操作系统的任务调度器
2、sleep yield区别
共同点:
1.都是Thread类中的类方法
2.都会导致正在执行的线程释放CPU
区别:
1.线程进入的状态不同:sleep方法导致线程进入到阻塞状态,yield方法导致线程进入就绪状态
2.是否考虑线程优先级:sleep方法不会考虑线程优先级,当一个线程调用sleep方法释放CPU后,所有优先级级别的线程都有机会获得CPU。yield方法会考虑线程优先级。当一个线程调用sleep方法释放CPU后,与该线程具有同等优先级,或优先级比该线程高的线程有机会获得CPU
3.可移植性:sleep方法比yield方法具有更好的可移植性
4.是否抛出异常:sleep方法声明抛出InterruptedException,而yield方法没有声明任何异常
5.是否有参数:sleep方法在Thread类中有两种重载形式,sleep(long ms),sleep(long ms,int nanos)yield方法没有参数
3、线程优先级
-
线程优先级会提示(hint)调度器优先调度该线程,但它仅仅是一个提示,调度器可以忽略它
-
如果 cpu 比较忙,那么优先级高的线程会获得更多的时间片,但 cpu 闲时,优先级几乎没作用
所以不一定优先级设置高就一定能有限执行,具体执行依赖任务调度器。
Runnable task1 = () -> {int count = 0;for (;;) {System.out.println("---->1 " + count++);}
};
Runnable task2 = () -> {int count = 0;for (;;) {// Thread.yield();System.out.println(" ---->2 " + count++);}
};
Thread t1 = new Thread(task1, "t1");
Thread t2 = new Thread(task2, "t2");
// t1.setPriority(Thread.MIN_PRIORITY);
// t2.setPriority(Thread.MAX_PRIORITY);
t1.start();
t2.start();
这里读者可将注释去掉自行实践,即可体会yield与优先级的使用。