关于线程的休眠

!!! note 目录

关于线程的休眠

一、sleep方法(休眠线程)

  1. 静态方法 sleep(long millis)

    • 方法签名:static void sleep(long millis)
    • 说明
      • 这是一个静态方法。
      • 没有返回值。
      • 参数是一个毫秒数。1秒 = 1000毫秒。
  2. 方法作用

    • 让当前线程进入休眠状态,也就是让当前线程放弃占有的CPU时间片,使其进入阻塞状态。
    • 具体含义:当前线程不再占用CPU,让给其他线程使用。
    • 阻塞时长:根据传入的毫秒参数决定。在指定的时间范围内,当前线程没有权利抢夺CPU时间片。
  3. “当前线程”解释

    • Thread.sleep(1000); 这行代码在哪个线程中执行,那么当前线程就是那个线程。
  4. 关于 run 方法

    • 在重写 run 方法时,不能在方法声明位置使用 throws 抛出异常。
  5. 使用 sleep 方法的场景

    • sleep 方法可以用来模拟每隔固定时间调用一次程序。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package com.camellia.thread.ThreadLifecycle;

public class ThreadSleepTest {

/**
* 程序的入口点。
* 主线程将在开始时休眠5秒,然后打印出一系列消息。
* 接着启动一个新的线程,该线程每隔一秒打印一次消息。
*
* @param args 命令行参数
*/
public static void main(String[] args) {
try {
// 让当前线程休眠5秒(代码出现在主线程中,所以主线程休眠5秒)
Thread.sleep(1000 * 5);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}

// 主线程输出
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "===>" + i);
}

// 创建并启动新的线程
Runnable myThread = new com.camellia.thread.sleep.MyThread();
Thread thread = new Thread(myThread);
thread.start();
}
}

/**
* 自定义的Runnable实现类。
* 在run方法中,每隔一秒打印一次消息。
*/
class MyThread implements Runnable {

/**
* 实现Runnable接口中的run方法。
* 当线程启动时,会执行此方法。
*/
@Override
public void run() {
// 子线程输出,每隔一秒打印一次消息
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "===>" + i);
try {
// 让当前线程休眠1秒
Thread.sleep(1000 * 1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

二、sleep方法注意事项(面试)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package com.camellia.thread.sleep;

/**
* 演示 Thread.sleep() 方法的使用和效果。
* 说明:Thread.sleep() 是一个静态方法,它让当前线程休眠指定的时间。
* 虽然可以通过线程实例调用,但实际上是让当前线程休眠,而不是调用线程实例。
*/
public class ThreadSleep02 {

public static void main(String[] args) throws InterruptedException {
// 创建线程实例
Thread t = new MyThread02();
t.setName("MyThread");

// 调用sleep方法,让当前线程(即主线程)休眠6秒
// 虽然是通过线程实例调用,但实际上是让主线程休眠
Thread.sleep(1000 * 6);

// 启动线程
t.start();

// 判断这个休眠效果作用在哪个线程
// sleep是静态方法,虽然是用实例调用,但是实际上作用于当前线程
}
}

/**
* 自定义的线程类,继承自Thread。
* 在run方法中打印当前线程的名称和一个计数值。
*/
class MyThread02 extends Thread {

/**
* 重写run方法,在线程启动后执行。
*/
@Override
public void run() {
// 循环打印当前线程的名称和计数值
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
}

三、interrupt方法(唤醒线程)

  • interrupt 是实例方法

    • 哪个实例对象调用 interrupt 方法,就终止哪个线程的睡眠。
  • 底层实现原理

    • 利用了异常处理机制。
  • 工作原理

    • 当调用 interrupt 方法时,如果线程正在睡眠,会抛出 InterruptedException 异常。
    • 然后捕获异常终止睡眠。
  • 注意事项

    • 如果在 catch 子句中继续抛出异常则不会中断,因为抛出异常等于没处理。
    • 可以在 catch 子句中打印异常信息,也可以执行自定义语句。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.camellia.thread.sleep;

/**
* 如何解除线程的睡眠(怎么解除线程因sleep导致的阻塞,让其开始抢夺CPU时间片。)
*/
public class ThreadSleep03 {

public static void main(String[] args) {
// 创建并启动线程
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " begin");
try {
// 线程休眠一年
Thread.sleep(1000 * 60 * 60 * 24 * 365);
} catch (InterruptedException e) {
// 捕获InterruptedException异常,并终止休眠
System.out.println(Thread.currentThread().getName() + " was interrupted.");
}
// 睡眠一年后或者被中断后,继续执行
System.out.println("Thread " + Thread.currentThread().getName() + " is running.");
}
});
thread.start();

// 主线程
// 需求:5秒后,唤醒正在睡眠的Thread-0线程
try {
Thread.sleep(1000 * 5);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
}
}