难度
初级
学习时间
30分钟
适合人群
零基础
开发语言
Java
开发环境
- JDK v11
- IntelliJ IDEA v2018.3
友情提示
- 本教学属于系列教学,内容具有连贯性,本章使用到的内容之前教学中都有详细讲解。
- 本章内容针对零基础或基础较差的同学比较友好,可能对于有基础的同学来说很简单,希望大家可以根据自己的实际情况选择继续看完或等待看下一篇文章。谢谢大家的谅解!
1.倒计时
今天我们开始学习 线程 睡眠sleep()方法。
在学习之前,我们来看一个生活中的例子:

这是一个倒计时。我想问大家一个问题,如何用代码来实现这个倒计时呢?
可能之前我们学过的知识都没法完成这个需求,但是,在今天我们终于可以实现了。
2.普通方式无法实现倒计时
刚刚说过,我们使用前面所学的知识还不能实现倒计时需求,为什么不能实现呢?
我们来看过就知道了。
演示:
请实现倒计时。
请观察程序代码及结果。
代码:
Main类:

结果:

从运行结果来看,并不符合我们的要求。
为什么呢?
因为它是一下子倒计时从10到1,不是一秒一个数字。
所以说,普通方式不能实现我们的倒计时需求。
如果有一个办法能让程序执行一次 for循环 停1秒,那么我们的倒计时需求就实现了。请问有解决办法吗?
还真有,这个解决办法就是我们的 线程睡眠sleep()方法 。
下面我们就来介绍它。
3.线程睡眠sleep()方法
为什么小节标题叫做“ 线程睡眠sleep()方法 ”?
因为我们的 sleep()方法的作用就是让线程睡眠 ,所以小节标题叫“ 线程睡眠sleep()方法 ”。
“ 让线程睡眠 ”是什么意思?
线程大家都知道是什么,睡眠的意思就是 暂时停止执行 。所以, 让线程睡眠的意思就是让线程暂时停止执行 。
再者,单词sleep中文就是睡眠的意思。
线程睡眠之后还会醒来吗?
会的。 线程睡眠就是线程暂时停止执行,这个暂时停止执行的时间由我们指定,时间一到,线程就会恢复正常执行。
下面,我们就来看看sleep()方法在Thread类中的位置及内容:

将注释翻译成中文:

从图中我们可以看到有两个sleep()方法:
- static void sleep(long millis)
- static void sleep(long millis, int nanos)
有小伙伴说图片中说的什么,看不清。
下面,我们将分别讲解这两个方法。
4. static void sleep( long millis)
public static void sleep(long millis) 方法原型:

sleep(long millis)方法作用是 使当前正在执行的线程休眠(暂时停止执行)指定的毫秒数。
访问权限
public :sleep(long millis)方法访问权限是公开的。
static :sleep(long millis)方法是 静态方法 ,意味着使用类名即可访问。
void :sleep(long millis)方法没有返回值。
参数
millis :long类型。以毫秒为单位的睡眠时间。
抛出的异常
throws IllegalArgumentException :如果millis的值是负数。
throws InterruptedException :当有任何线程中断了当前线程时,就会抛出此异常。InterruptedException中的Interrupted中文有打断、中断的意思。抛出此异常时,将清除当前线程的中断状态。
应用
下面,我们就来使用sleep(long millis)方法实现倒计时需求。
演示:
请使用sleep(long millis)方法实现倒计时需求。
请观察程序代码及结果。
代码:
Main类:

结果:

从运行结果来看,符合我们的预期。
回顾我们的程序,我们在for循环中添加了一个sleep(long millis)方法:

然后运行程序,执行结果:

结果也到达了我们的需求。

重要代码是在sleep(long millis)方法中的millis参数上,因为单位是毫秒数,所以我们要暂停1秒(1秒=1000毫秒),sleep(long millis)方法参数传入1000即可。
5.static void sleep(long millis, int nanos)
public static void sleep(long millis, int nanos) 方法原型:

sleep(long millis, int nanos)方法作用是 使当前正在执行的线程休眠(暂时停止执行)指定的毫秒数加上指定的纳秒数。
访问权限
public :sleep(long millis, int nanos)方法访问权限是公开的。
static :sleep(long millis, int nanos)方法是静态方法,意味着使用类名即可访问。
void :sleep(long millis, int nanos)方法没有返回值。
参数
millis :long类型。以毫秒为单位的睡眠时间。
nanos :int类型。以纳秒为单位的睡眠时间,其取值范围在0-999999之间。
抛出的异常
throws IllegalArgumentException :如果millis的值是负数或者nanos取值范围不在0-999999之间。
throws InterruptedException :当有任何线程中断了当前线程时,就会抛出此异常。InterruptedException中的Interrupted中文有打断、中断的意思。抛出此异常时,将清除当前线程的中断状态。
应用
下面,我们就来使用sleep(long millis, int nanos)方法实现倒计时需求。
在演示之前我们先来看一个时间单位之间的转换:
由于nanos的取值范围只能是0-999999之间,所以大家需要注意。
有小伙伴就问了:为什么nanos取值范围要限制在0-999999之间?
其实, 当我们nanos取值大于500000就可以促使millis++(即millis累加1毫秒) 。这一点我们也可以从sleep(long millis, int nanos)方法源码中看出来:

好了,说完了该注意的点,接下来演示sleep(long millis, int nanos)方法用法。
演示:
请使用sleep(long millis, int nanos)方法实现倒计时需求。
请观察程序代码及结果。
代码:
Main类:

结果:

从运行结果来看,符合我们预期。
简单的回顾我们程序代码,我们在for循环中添加了一个sleep(long millis, int nanos)方法:

特别注意,这里我们给millis参数设置的值是999,而nanos参数设置的值是500000。

为什么millis是999,nanos是500000?
因为nanos>=500000时,millis就会+1,所以999毫秒+1毫秒=1000毫秒,而1000毫秒就是1秒,即这里会让线程睡眠1秒,实现倒计时需求。
6.sleep(long millis, int nanos)方法和sleep(long millis)方法谁更常用?
sleep(long millis)方法比sleep(long millis, int nanos)方法更常用。
sleep(long millis)方法是我们在实际开发中经常会用到的方法。希望大家可以掌握它。
7.sleep(long millis)方法应用
我们 经常使用sleep(long millis)方法来做一些延迟操作 。
例如,使当前线程暂停几秒之后再执行。

运行程序,执行结果:

只要是需求延迟操作的地方都可以使用sleep(long millis)方法。
8.sleep()方法说的当前线程怎么获取?
两个sleep()方法作用都是使当前线程暂时停止执行,那么这个当前线程指的又是哪个线程呢?
这个当前线程指的是正在执行程序代码的线程。
还是不明白是哪个线程,可以获取到这个线程吗?
可以。我们在 一章中讲到过获取当前线程的方法,那就是 currentThread()方法 。
下面来获取当前被暂时停止执行的线程。
演示:
请获取当前线程并打印其名称。
请让当前线程睡眠5秒钟。
请观察程序代码及结果。
代码:
Main类:

结果:

从运行结果来看,我们程序先打印的是当前线程名称“main”,然后暂停了5秒后执行后面的代码。
程序代码也很简单,我们只是使用了currentThread()方法获取到当前线程:

然后又获取了当前线程的名称:

接着打印了其名称:

结果:

接着,我们让当前线程又停了5秒:

当线程恢复过来时,继续执行完剩下的代码:

结果:

9.计算一段程序执行时间
如何计算我们某一段程序执行时间呢?
其实很简单, 我们在要程序开始前获取一次时间,然后在程序执行后获取一次时间,最后将最后获取到的时间减去最开始获取到的时间,得到的时间差就得到我们的程序执行时间 。
尽管这个方法不科学,但是这个方法最便捷。
在演示之前呢,我们需要提前了解一个方法,这个方法可以获取到当前时间的毫秒数。这个方法就是 System.currentTimeMillis() 。

将注释翻译成中文:

System.currentTimeMillis()方法作用就是返回当前时间(单位:毫秒)。
下面就开始演示。
演示:
请获取程序执行时间。
请观察程序代码及结果。
代码:
Main类:

结果:

从运行结果来看,符合我们的预期。计算出了程序执行的时间。
回顾程序,看看是如何做的。
首先,我们在mian()方法开始时,获取了一次当前时间:

然后我们正常书写要执行的代码:

接着,我们又获取了一次当前时间:

最后,我们用最后一次获取的时间减去最开始获取的时间,算出程序执行时间:

执行结果:

通过这个方式我们就可以获取某一段程序的执行时间。
10.多个线程时,如何睡眠指定的线程?
当我们程序中有多个线程时,如何睡眠指定的线程?
有小伙伴可能说那就是用指定的线程对象调用其sleep()方法即可。
结果是不是这样呢?我们来试试。
演示:
请睡眠指定的线程。
请观察程序代码及结果。
代码:
Main类:

结果:

从运行结果来看,并不符合我们预期。为什么不是5秒?竟然花费了10秒。
来看看程序代码,找出原因。
首先,我们在程序开始执行时获取了一次时间:

然后,我们创建了一个新线程:

接着,我们启动了新线程:

然后,我们调用新线程的sleep()方法,睡眠了5秒钟:

接着,我们将主线程也睡眠了5秒钟:

然后,我们书写了需求执行的代码:

接着,我们又获取了一次当前时间:

最后,我们将最后获取的时间减去开始获取的时间得到时间差:

执行结果:

这个结果显然不是我们预期的。我们预期的结果应该是新线程睡眠5秒钟,主线程睡眠5秒钟,但结果却是10秒钟。

这个10秒钟是两次调用sleep()方法产生的结果,也就是说,我们使用线程对象去调用sleep()方法是无效的,还得看sleep()方法当前所在的线程。
例如,这两次sleep()方法调用所在的线程都是在主线程中。如果我们将新线程的睡眠方法移到新线程对象里面去,结果又会不一样。
改写我们的Main方法:

运行程序,执行结果:

这次是符合我们预期的。总共只花费5秒钟时间。
综上所述, 我们要暂停哪个线程,就得在哪个线程里面调用sleep()方法。
总结
- sleep(long millis)方法作用是使当前正在执行的线程休眠(暂时停止执行)指定的毫秒数。
- sleep(long millis, int nanos)方法作用是使当前正在执行的线程休眠(暂时停止执行)指定的毫秒数加上指定的纳秒数。
- 睡眠的意思就是暂时停止执行。
- 让线程睡眠的意思就是让线程暂时停止执行。
- 线程睡眠就是线程暂时停止执行,这个暂时停止执行的时间由我们指定,时间一到,线程就会恢复正常执行。
- 经常使用sleep(long millis)方法来做一些延迟操作。
- 我们在要程序开始前获取一次时间,然后在程序执行后获取一次时间,最后将最后获取到的时间减去最开始获取到的时间,得到的时间差就得到我们的程序执行时间。
- 我们要暂停哪个线程,就得在哪个线程里面调用sleep()方法。
至此,Java中线程睡眠sleep()方法相关内容讲解先告一段落,更多内容请持续关注。
答疑
如果大家有问题或想了解更多前沿技术,请在下方留言或评论,我会为大家解答。
上一章
下一章
“全栈2019”Java多线程第六章:中断线程interrupt()方法详解
学习小组
加入同步学习小组,共同交流与进步。
- 方式一:关注头条号Gorhaf,私信“Java学习小组”。
- 方式二:关注公众号Gorhaf,回复“Java学习小组”。
全栈工程师学习计划
关注我们,加入“全栈工程师学习计划”。

版权声明
原创不易,未经允许不得转载!