Java并发(七)----线程sleep、yield、线程优先级

发布时间 2023-05-30 22:11:05作者: |旧市拾荒|

1、sleep 与 yield

sleep

  1. 调用 sleep 会让当前线程从 Running 进入 Timed Waiting 状态(阻塞)

  2. 其它线程可以使用 interrupt 方法打断正在睡眠的线程,这时 sleep 方法会抛出 InterruptedException

  3. 睡眠结束后的线程未必会立刻得到执行

  4. 建议用 TimeUnit 的 sleep 代替 Thread 的 sleep 来获得更好的可读性(TimeUnit.SECONDS.sleep(1);)

调用sleep

    public static void main(String[] args) {
        Thread t1 = new Thread("t1") {
            @Override
            public 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") {
            @Override
            public 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 interrupted
    at java.lang.Thread.sleep(Native Method)
    at cn.itcast.test.Test7$1.run(Test7.java:14)

yield

  1. 调用 yield 会让当前线程从 Running 进入 Runnable 就绪状态,然后调度执行其它线程,注意:如果没有其他线程的话,可能还是执行当前线程

  2. 具体的实现依赖于操作系统的任务调度器

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与优先级的使用。