0.sleep和wait的区别
sleep()
是使线程暂停执行一段时间的方法。wait()
也是一种使线程暂停执行的方法。例如,当线程执行wait()
方法时候,会释放当前的锁,然后让出CPU的执行权,进入等待状态。并且可以调用notify()
方法或者notifyAll()
方法通知正在等待的其他线程。notify()
方法仅唤醒一个线程(等待队列中的第一个线程)并允许他去获得锁。notifyAll()
方法唤醒所有等待这个对象的线程并允许他们去竞争获得锁。具体区别如下:
1.原理不同。sleep()
方法是Thread
类的静态方法,是线程用来控制自身流程的,他会使此线程暂停执行一段时间,而把执行机会让给其他线程,等到计时时间一到,此线程会自动苏醒。例如,当线程执行报时功能时,每一秒钟打印出一个时间,那么此时就需要在打印方法前面加一个sleep()
方法,以便让自己每隔一秒执行一次,该过程如同闹钟一样。而wait()
方法是Object
类的方法,用于线程间通信,这个方法会使当前拥有该对象锁的进程等待,直到其他线程调用notify()
方法或者notifyAll()
时才醒来,不过开发人员也可以给他指定一个时间,自动醒来。
2.对锁的 处理机制不同。由于sleep()
方法的主要作用是让线程暂停执行一段时间,时间一到则自动恢复,不涉及线程间的通信,因此,调用sleep()
方法并不会释放锁。而wait()
方法则不同,当调用wait()
方法后,线程会释放掉他所占用的锁,从而使线程所在对象中的其他synchronized
数据可以被其他线程使用。
3.使用区域不同。wait()
方法必须放在同步控制方法和同步代码块中使用,sleep()
方法则可以放在任何地方使用。sleep()
方法必须捕获异常,而wait()
、notify()
、notifyAll()
不需要捕获异常。在sleep
的过程中,有可能被其他对象调用他的interrupt()
,产生InterruptedException
。由于sleep
不会释放锁标志,容易导致死锁问题的发生,因此一般情况下,推荐使用wait()
方法。
1.wait方法
wait方法是Object
提供方法,可通过wait
方法让当前线程进入等待。
1.1 先看看wait方法的介绍。
通过查阅JDK1.8文档发现Object
中的wait
方法有三个重载方法。
分别为:
- void wait()
导致当前线程等待,直到另一个线程为此对象调用notify()
方法或notifyAll()
方法。实际上wait()
方法是仅仅是调用wait(0L)
。
- void wait(long timeout)
导致当前线程等待,直到另一个线程调用此对象的notify()
方法或notifyAll()
方法,或者已经过了指定的时间量,如果timeout为0L那么将为永久等待相当于调用wait()
。
- void wait(long timeout, int nanos)
导致当前线程等待,直到另一个线程为此对象调用notify()
方法或notifyAll()
方法,或者某个其他线程中断当前线程,或者已经过了一定量的实时。
1.2 wait方法的特点
1.wait方法只能在synchronized
代码块内调用,否则会抛出IllegalMonitorStateException
异常。也就是说调用wait
方法的线程必须持有锁。
示例代码
package spring.cache.jvm;
public class Demo implements Runnable{
@Override
public void run() {
System.out.println("start");
long start = System.currentTimeMillis();
try {
this.wait(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("end");
System.out.println(end-start);
}
public static void main(String[] args) {
Demo demo = new Demo();
Thread thread1 = new Thread(demo);
thread1.start();
}
}
控制台
start
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at spring.cache.jvm.Demo.run(Demo.java:25)
at java.lang.Thread.run(Thread.java:748)
进程完成,退出码 0
2.线程调用wait
方法时该线程释放此锁(监视器)的所有权并进入等待状态,并把CPU的执行权让给其他线程,直到其他线程调用notify
方法或notifyAll
方法唤醒。
public class Demo implements Runnable{
@Override
public void run() {
System.out.println("start");
synchronized (this){
try {
System.out.println("当前线程名字为:"
+Thread.currentThread().getName());
//唤醒其它正在等待的线程
this.notify();
//导致线程等待,并释放锁。
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("end");
}
public static void main(String[] args) {
Demo demo = new Demo();
Thread thread1 = new Thread(demo);
thread1.start();
Thread thread2 = new Thread(demo);
thread2.start();
}
}
控制台
start
start
当前线程名字为:Thread-0
当前线程名字为:Thread-1
end
1.3 wait方法实现
1.wait()
源码
public final void wait() throws InterruptedException {
this.wait(0L);
}
wait()
方法其实是调用wait(long timeout)
方法并传入参数0L
2.wait(long timeout)
源码
public final native void wait(long timeout) throws InterruptedException;
wait(long timeout)
方法被native
修饰了,也就是说他不是java方法,他是一个本地方法,底层实现的可能是C和C++。
3.wait(long timeout, int nanos)
源码
public final void wait(long timeout, int nanos) throws InterruptedException {
if (timeout < 0L) {//timeout小于0则报错
throw new IllegalArgumentException("timeout value is negative");
} else if (nanos >= 0 && nanos <= 999999) {//nanos 大于等于 0 && 小于等于 999999
if (nanos > 0) { //nanos 大于 0
++timeout; //timeout自增1
}
this.wait(timeout); //调用wait(long timeout)
} else {
throw new IllegalArgumentException("nanosecond timeout value out of range");
}
}
wait(long timeout, int nanos)
文档中的介绍解释的不是很清楚,通过翻阅源码发现其实wait(long timeout, int nanos)
底层也是调用wait(long timeout)
方法,只不过做了些处理,如果nanos
有值的话,并且nanos
大于0,则timeout
加1。举个例子:例如this.wait(1000,999)
那么这时候线程实际等待时间为1001
。
2.sleep方法
sleep
是Thread
对象提供的方法,可通过sleep
方法让当前线程进入休眠。
2.1 先看看sleep方法的介绍。
通过查阅JDK1.8文档发现Thread
中的sleep
方法有两个重载方法。
- static void sleep(long timeout)
使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行),具体取决于系统定时器和调度程序的精度和准确性。
- static void sleep(long timeout, int nanos)
导致正在执行的线程以指定的毫秒数加上指定的纳秒数来暂停(临时停止执行),这取决于系统定时器和调度器的精度和准确性。
2.2 sleep方法的特点
1.sleep可以在synchronized
代码块内调用,也就是说调用sleep
的线程不用持有锁。
示例代码
package spring.cache.jvm;
public class Demo implements Runnable{
@Override
public void run() {
long start = System.currentTimeMillis();
try {
//让线程休眠1秒
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("执行时间:"+(end-start));
}
public static void main(String[] args) {
Demo demo = new Demo();
Thread thread = new Thread(demo);
thread.start();
}
}
控制台
执行时间:1000
进程完成,退出码 0
2.sleep
方法让线程休眠并不会释放锁,但会交出CPU的执行权。
示例代码
package spring.cache.jvm;
public class Demo implements Runnable{
@Override
public void run() {
long start = System.currentTimeMillis();
synchronized (this){
try {
//让线程休眠1秒
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
long end = System.currentTimeMillis();
System.out.println(Thread.currentThread().getName()+"的执行时间:"
+(end-start));
}
public static void main(String[] args) {
Demo demo = new Demo();
Thread thread = new Thread(demo);
thread.start();
Thread thread1 = new Thread(demo);
thread1.start();
}
}
控制台
Thread-0的执行时间:1000
Thread-1的执行时间:2000
进程完成,退出码 0
1.线程Thread-0
进入synchronized
代码块,得到同步锁并进入休眠1秒,Thread-1
尝试获取锁,获取不到(锁此时被Thread-0
占用)。
2.Thread-0
唤醒出synchronized
代码块释放锁并打印,Thread-1
获取到锁进行等待1秒后打印。
2.sleep方法让线程休眠并不会释放锁,但会交出CPU的执行权。
2.3 sleep方法实现
1.sleep(long timeout)
源码
public static native void sleep(long timeout) throws InterruptedException;
sleep(long timeout)
方法被native
修饰了,也就是说他不是java方法,他是一个本地方法,底层实现的可能是C和C++。
2.sleep(long timeout, int nanos)
源码
public static void sleep(long timeout, int nanos) throws InterruptedException {
if (timeout< 0L) { //过期时间小于0L 抛出 超时值为负 异常。
throw new IllegalArgumentException("timeout value is negative");
} else if (nanos>= 0 && nanos<= 999999) {//nanos 大于等于 0 && 小于等于 999999
if (nanos >= 500000 || (nanos!= 0 && timeout== 0L)) { // nanos 大于等于 500000 或者nanos 不等于 0 并且 timeout 等等于 0L
++timeout; //timeout自增
}
sleep(timeout);
} else {
throw new IllegalArgumentException("nanosecond timeout value out of range");
}
}
sleep(long timeout, int nanos)
文档中的介绍解释的不是很清楚,通过翻阅源码发现其实sleep(long timeout, int nanos)
底层也是调用sleep(long timeout)
方法,只不过做了些处理,具体看上面源码解读。
3.sleep和wait方法区别总结
wait
由Object
提供,sleep
由Thread
提供。wait
方法只能在synchronized
代码块内调用,而sleep
没有做限制。wait
方法让线程陷入等待/休眠阶段时,会释放同步锁。而sleep
并不会释放同步锁。wait
方法可以不指定时间戳(线程的休眠时间)将由notify()
方法或notifyAll()
方法唤醒。而sleep
必需指定时间戳(线程的休眠时间)。
以上就是wait
和sleep
的一个区别,有一篇文章讲的还是蛮不错的。如果大家看完还是不能够很好总结可以参考一下这篇文章:
https://blog.csdn.net/qiuchaoxi/article/details/79837568