sleepwait方法之间区别
Posted 向北zz
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sleepwait方法之间区别相关的知识,希望对你有一定的参考价值。
sleep、wait方法之间区别
1.所属的类不同
sleep是Thread类的静态方法,而wait是Object类的成员方法
2.锁机制不一样
- sleep方法:会让出资源调度器为当前线程分配的时间片,也就是放弃cpu的使用权,但是sleep不会释放当前线程持有的锁资源。其缺点就是当其它线程想获得同样的锁资源会被阻塞。
- wait方法:既放弃cpu使用权,也会释放锁资源。即不会阻塞其它线程
请看如下代码:创建两个线程t1、t2,t1获得锁后睡眠5s
@Slf4j
public class TestSleepAndWait {
static final String lock = "abc";
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(()->{
synchronized (lock){
log.error("t1线程执行");
try {
//
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"t1");
Thread t2 = new Thread(()->{
// t2获得锁后执行
synchronized (lock){
log.error("t2线程执行");
}
},"t1");
t1.start();
t2.start();
}
}
执行结果:
16:51:01 [t1] gzhu.study.test.TestSleepAndWait - t1线程执行
16:51:06 [t1] gzhu.study.test.TestSleepAndWait - t2线程执行
由日志时间可以看到t2线程执行时间刚好在5s之后,说明t1睡眠过程中,t2一直在阻塞等待t1释放锁。
接下来我们尝试把sleep方法换成wait方法,上述其它代码不变
// t1线程等待
lock.wait();
查看运行结果:
16:57:55 [t1] gzhu.study.test.TestSleepAndWait - t1线程执行
16:57:55 [t1] gzhu.study.test.TestSleepAndWait - t2线程执行
可以看到t1、t2线程几乎在同一时间运行,说明wait方法使线程释放了说资源。值得注意的是,wait方法需要配合锁对象使用,即使用锁对象使当前线程阻塞。
3.调用之后的线程的状态不同
sleep方法调用后,线程进入TIME_WAITING状态,而wait方法调用后,线程会进入WAITING状态。
额外了解一下:什么是等待池?什么是锁池?
等待池就是:线程调用wait方法后,线程会进入一个LIFO(为什么是LIFO下面解释)等待被唤醒,在等待池的线程被唤醒之前是不会去竞争锁资源的。
锁池:存放竞争锁资源的线程,等待池的线程被notify()和notifyAll()方法唤醒之后,会先进入锁池而不是直接获得锁资源执行。另外有一个误区,笔者看到许多博客说sleep方法需要指定时间,而wait方法不需要指定时间其实是错的,如下:
public final native void wait(long timeout) throws InterruptedException;
public final void wait(long timeout, int nanos) throws InterruptedException
第一种情况:
@Slf4j
public class TestSleepAndWait {
static final String lock = "abc";
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(()->{
synchronized (lock){
log.error("t1线程执行");
try {
// t1线程等待
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
log.error("t1线程继续执行");
}
},"t1");
Thread t2 = new Thread(()->{
// t2获得锁后执行
synchronized (lock){
log.error("t2线程执行");
}
},"t1");
Thread t3 = new Thread(()->{
// t2获得锁后执行
synchronized (lock){
log.error("t3线程执行");
}
},"t3");
t1.start();
t2.start();
t3.start();
}
}
结果:
17:33:03 [t1] gzhu.study.test.TestSleepAndWait - t1线程执行
17:33:03 [t3] gzhu.study.test.TestSleepAndWait - t3线程执行
17:33:03 [t1] gzhu.study.test.TestSleepAndWait - t2线程执行
由于没有唤醒t1线程,即使t2、t3线程释放锁资源后,t1线程也没有继续执行。
第二种情况:
Thread t1 = new Thread(()->{
synchronized (lock){
log.error("t1线程执行");
try {
// t1线程等待
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
log.error("t1线程继续执行");
}
},"t1");
Thread t2 = new Thread(()->{
// t2获得锁后执行
synchronized (lock){
log.error("t2线程执行");
lock.notify();
while (true){
}
}
},"t1");
t1.start();
t2.start();
运行结果:
17:38:23 [t1] gzhu.study.test.TestSleepAndWait - t1线程执行
17:38:23 [t1] gzhu.study.test.TestSleepAndWait - t2线程执行
即使t1被t2唤醒进入锁池,但是由于t2一直循环未释放锁资源,使得t1也不能立即继续执行。
notify()方法与notifyAll()方法
notifAll方法,是将等待池中所有线程唤醒,并按照LIFO原则唤醒
notify方法是从等待队列中随机唤醒,如果只有一个线程则唤醒一个线程。
以上是关于sleepwait方法之间区别的主要内容,如果未能解决你的问题,请参考以下文章