sleep和wait详解与区别

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方法

sleepThread对象提供的方法,可通过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方法区别总结

  • waitObject提供,sleepThread提供。
  • wait方法只能在synchronized代码块内调用,而sleep没有做限制。
  • wait方法让线程陷入等待/休眠阶段时,会释放同步锁。而sleep并不会释放同步锁。
  • wait方法可以不指定时间戳(线程的休眠时间)将由notify()方法或notifyAll()方法唤醒。而sleep必需指定时间戳(线程的休眠时间)。

以上就是waitsleep的一个区别,有一篇文章讲的还是蛮不错的。如果大家看完还是不能够很好总结可以参考一下这篇文章:
https://blog.csdn.net/qiuchaoxi/article/details/79837568

  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值