java-Thread重要的API—上—sleep(),yield(),setPriority()以及sleep(0)的妙用。

  • Post author:
  • Post category:java


哈喽,小伙伴们,大家好!今天给大家分享的是Thread里面重要的方法,为了便于大家掌握,我分为三部分进行讲解,首先是第一部分,这些方法是在开发中比较常用的API,常用的和不常用的,我都会给大家提示,希望大家都有所收获,好了,进入正题。



1 sleep()方法(常用)

sleep 是一个静态方法,其有两个重载方法,其中一个需要传入毫秒数,另外一个既需 要毫秒数也需要纳秒数。


1.1 方法介绍以及实现


sleep 方法会使当前线程进入指定毫秒数的休眠,暂停执行,虽然给定了一个休眠的时间, 但是最终要以系统的定时器和调度器的精度为准,休眠有一个非常重要的特性,那就是其不会放弃 monitor 锁的所有权。下面举个例子进行说明:

public class ThreadSleep {

    public static void main(String[] args) {
        // 子线程
        new Thread(() -> {
            long startTime = System.currentTimeMillis();
            sleep(2000L);
            long endTime = System.currentTimeMillis();
            System.out.printf("Total spend %d ms\n", endTime - startTime);
        }).start();

        // main 线程
        long startTime = System.currentTimeMillis();
        sleep(3000L);
        long endTime = System.currentTimeMillis();
        System.out.printf("Main thread spend %d ms", endTime - startTime);
    }

    private static void sleep(long ms) {
        try {
            Thread.sleep(ms);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

我们分别在自定义的线程和主线程中进行了休眠,每个线程的休眠互不影响,从结果看,Thread.sleep 只会导致当前线程进入指定时间的休眠。


1.2 使用 TimeUniT 替代 Thread.sleep


在 JDK1.5 以后,JDK 引入了一个枚举 TimeUnit,其对 sleep 方法提供了很好的封装, 使用它可以省去时间单位的换算步骤,比如线程想休眠 3 小时 24 分 17 秒 88 毫秒,使用 TimeUnit 来实现就非常简便优雅了:

 public static void main(String[] args) {
        try {
            // 第一种方式:Thread.sleep
            Thread.sleep(12257088L);

            // 第二种方式:TimeUnit.HOURS.sleep
            TimeUnit.HOURS.sleep(3);
            TimeUnit.MINUTES.sleep(24);
            TimeUnit.SECONDS.sleep(17);
            TimeUnit.MILLISECONDS.sleep(88);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

同样的时间表达,TimeUnit 显然清晰很多,强烈建议在使用 Thread.sleep 的地方, 完全使用 TimeUnit 来代替,因为 sleep 能做的事情,TimeUnit 全部都能完成,并且可以做的更好。


1.3 Thread.sleep(0)

Thread.sleep(0) 表示挂起 0 毫秒,但是Thread.sleep(0) 并非是真的要线程挂起 0 毫秒,目的

在于这次调用 Thread.sleep(0)的当前线程确实的被冻结了一下,让其他线程有机会优先执行。Thread.sleep(0)是你的线程暂时放弃 cpu,也就是释放一些未用的时间片给其他线程或进程使用,就相当于一个让位动作。


在线程中,调用 sleep(0)可以释放 cpu 时间,

让线程马上重新回到就绪队列而非等待队列,

sleep(0)释放当前线程所剩余的时间片(如果有剩余的话),这样可以让操作系 统切换其他线程来执行,提升效率。





2 yield()方法(不常用)

yield 方法属于一种启发式的方法,其会提醒调度器我愿意放弃当前的 CPU 资源,如果 CPU 的资源不紧张,则会忽略这种提醒。调用 yield 方法会使当前线程从 Running 状态切换到 Runnable 状态,因为这个方法是不可控的,所以一般这个方法我们不会常用。所以这里我代码就不贴上来了,就讲一下yield方法和sleep方法的区别。在 JDK1.5 以前的版本中 yield 的方法事实上是调用了 sleep(0),但是他们之间存在着本质的区别,具体如下:

  • sleep 会导致当前线程暂停指定的时间,没有 CPU 时间片的消耗。
  • yield 只是对 CPU 调度器的一个提示,如果 CPU 调度器没有忽略这个提示,它会导致线程上下文的切换。
  • sleep 会使线程短暂 block,会在给定的时间内试放 CPU 资源
  • yield 会使 Running状态的Thread 进入Runnable 状态(如果CPU调度器没有忽略这个提示的话)
  • sleep 几乎百分之百的完成了给定时间的休眠,而 yield 的提示并不能一定保证



3 setPriority和getPriority方法(不常用)

设置线程的优先级,只需要调用 setPriority 方法即可。

public final void setPriority(int newPriority) {
        ThreadGroup g;
        checkAccess();
        if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
            throw new IllegalArgumentException();
        }
        if((g = getThreadGroup()) != null) {
            if (newPriority > g.getMaxPriority()) {
                newPriority = g.getMaxPriority();
            }
            setPriority0(priority = newPriority);
        }
    }

通过上面源码的分析,我们可以看出,线程的优先级不能小于1也不能大于10,如果指定的线程优先级大于线程所在 group 的优先级,那么指定的优先级将会失败,取而代之的是 group 的最大优先级。下面的代码会给我们证实:

public class ThreadPriority02 {

    public static void main(String[] args) {
        // 定义一个线程组
        ThreadGroup testGroup = new ThreadGroup("testGroup");
        // 将线程组的优先级指定为 7
        testGroup.setMaxPriority(7);
        // 定义一个线程,将该线程加入到 group 中
        Thread testThread = new Thread(testGroup, "testThread");
        // 企图将线程的优先级设定为 10
        testThread.setPriority(10);
        // 未设置成功 输出:7
        System.out.println(testThread.getPriority());
    }
}

一般情况下,不会对线程设定优先级别,更不会让某些业务严重的依赖线程的优先级别, 比如权重,借助优先级设定某个任务的权重,这种方式是不可取的,一般定义线程的时候使用默认的优先级就好了, 线程默认的优先级和它的父类保持一致,一般情况下都是 5,因为 main 线程的优先级就是 5,所以它派生出来的线程都是 5。



版权声明:本文为wjf_jone原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。