JUC并发编程 -- 线程常用方法之sleep() & yield() & 线程优先级 & sleep方法应用: 限制对 CPU 的使用
Posted Z && Y
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JUC并发编程 -- 线程常用方法之sleep() & yield() & 线程优先级 & sleep方法应用: 限制对 CPU 的使用相关的知识,希望对你有一定的参考价值。
1. sleep() 线程休眠
- 调用 sleep 会让当前线程从 Running 进入 Timed Waiting 状态(阻塞)
- 其它线程可以使用 interrupt 方法打断正在睡眠的线程,这时 sleep 方法会抛出 InterruptedException
- 睡眠结束后的线程未必会立刻得到执行(有可能这时的CPU正在执行其他线程的代码,所以该线程需要等到任务调度器 把新的时间片分给该线程以后,该线程才会继续执行。)
- 建议用 TimeUnit 的 sleep 代替 Thread 的 sleep 来获得更好的可读性
1.1 测试sleep()方法改变线程状态
调用 sleep 会让当前线程从 Running 进入 Timed Waiting 状态(阻塞)
测试sleep()方法改变线程状态:
import lombok.extern.slf4j.Slf4j;
@Slf4j(topic = "c.Test6")
public class Test6 {
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();
// 因为主线程先启动 所以这时的t1线程是RUNNABLE状态
log.debug("t1 state: {}", t1.getState());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 主线程休眠500ms后 t1线程一定启动了
log.debug("t1 state: {}", t1.getState());
}
}
运行结果:
1.2 打断(叫醒)睡眠的线程
其它线程可以使用 interrupt 方法打断正在睡眠的线程,这时 sleep 方法会抛出 InterruptedException
代码:
import lombok.extern.slf4j.Slf4j;
@Slf4j(topic = "c.Test7")
public class Test7 {
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();
}
}
运行结果:
1.3 TimeUnit 的 sleep
建议用 TimeUnit 的 sleep 代替 Thread 的 sleep 来获得更好的可读性
代码:
@Slf4j(topic = "c.Test8")
public class Test8 {
public static void main(String[] args) throws InterruptedException {
log.debug("enter");
TimeUnit.SECONDS.sleep(2);
log.debug("end");
}
}
运行结果:
补充:
其实该方法内部也是调用的Thread的sleep方法,只不过这里做了时间的单位换算
2. yield() 线程礼让
- 调用 yield 会让当前线程从 Running 进入 Runnable 就绪状态,然后调度执行其它线程(该线程本来有CPU的使用权,调用该方法后,会让出该方法的CPU使用权,就让其他线程有机会去使用CPU)
- 具体的实现依赖于操作系统的任务调度器(这时候可能没有其他的线程在运行,CPU还是会把时间片分给该线程)
3.sleep() vs yield()
- 调用sleep方法会让线程进入休眠状态(阻塞状态),CPU会把时间片分给该线程。
- 调用yield方法会让线程进入就绪状态,CPU还是有可能把时间片分给该线程。
- sleep方法可以加参数(线程休眠的时间),儿yield方法没有参数,调用yield方法只是一瞬间的事情。
4. 线程优先级
- 线程优先级会提示(hint)调度器优先调度该线程,但它仅仅是一个提示,调度器可以忽略它
- 如果 cpu 比较忙,那么优先级高的线程会获得更多的时间片,但 cpu 闲时,优先级几乎没作用
- 线程里面有一个setPriority(int newPriority)方法可以设置线程的优先级
补充:
不管是yield方法还是设置线程优先级,都不能控制线程的调度,最终都是由任务调度器来决定
4.1 测试代码01: 不加以阻止
代码:
import lombok.extern.slf4j.Slf4j;
@Slf4j(topic = "c.Test9")
public class Test9 {
public static void main(String[] args) {
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();
}
}
运行结果:
4.1 测试代码02: 加上yield方法
代码:
import lombok.extern.slf4j.Slf4j;
@Slf4j(topic = "c.Test9")
public class Test9 {
public static void main(String[] args) {
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();
}
}
运行结果:
4.1 测试代码03: 设置线程优先级
代码:
import lombok.extern.slf4j.Slf4j;
@Slf4j(topic = "c.Test9")
public class Test9 {
public static void main(String[] args) {
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);// t1线程设置为最小的优先级
t2.setPriority(Thread.MAX_PRIORITY);// t2线程设置为最大的优先级
t1.start();
t2.start();
}
}
运行结果:
1. sleep方法应用: 限制对 CPU 的使用
- 在没有利用 cpu 来计算时,不要让 while(true) 空转浪费 cpu,这时可以使用 yield 或 sleep 来让出 cpu 的使用权给其他程序
对应这段代码:
- 可以用 wait 或 条件变量达到类似的效果
- 不同的是,后两种都需要加锁,并且需要相应的唤醒操作,一般适用于要进行同步的场景
- sleep 适用于无需锁同步的场景
以上是关于JUC并发编程 -- 线程常用方法之sleep() & yield() & 线程优先级 & sleep方法应用: 限制对 CPU 的使用的主要内容,如果未能解决你的问题,请参考以下文章
JUC并发编程 -- 线程常用方法之join()详解 & join同步应用 & join限时同步
JUC并发编程 -- 回顾多线程(线程的六种状态 & wait / sleep 的区别)
JUC并发编程 -- 线程常用方法概述 & start() vs run()