sleep() 和wait() 有什么区别?

2020-12-15 14:42发布

8条回答
james
2楼 · 2020-12-16 14:01

sleep()是Thread类的静态方法,wait()属于Obejct类的成员方法;
sleep()可以不涉及线程通信,调用时指定这段时间此线程会暂停执行,但监控状态依然保持,不会释放对象锁,到时间自动恢复;wait()用于线程间的通信,调用时会放弃对象锁,进入等待队列,待调用notify()/notifyAll()唤醒指定的线程或者所有线程,才进入对象锁定池准备获得对象锁进入运行状态;
wait()\notify()以及notifyAll()只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用;
sleep()方法必须捕获异常InterruptedException,wait()\notify()以及notifyAll()不需要捕获异常。

注意:
  sleep方法只让出了CPU,而并不会释放同步资源锁。
  线程执行sleep()方法后会转入阻塞状态。
  sleep()方法指定的时间为线程不会运行的最短时间。因此,sleep()方法不能保证该线程睡眠到期后就开始执行。
  notify的作用相当于叫醒睡着的人,而并不会给他分配任务,就是说notify只是让之前调用wait的线程有权利重新参与线程的调度。

猜不到结尾
3楼 · 2020-12-16 09:56

sleep()是线程类Thread的方法;作用是导致此线程暂停执行指定时间,把执行机会给其他线程,但是监控状态依然保持,到时候会自动恢复;调用sleep()不会释放对象锁。

wait()是Object类的方法;对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池。只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池,准备获得对象锁进行运行状态。


yuixan
4楼 · 2020-12-16 11:01

sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,给执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。

flame
5楼 · 2020-12-16 11:06

sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,给执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。

wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。

1234567
6楼 · 2020-12-16 11:23

sleep()和wait()都是线程暂停执行的方法。

1、这两个方法来自不同的类分别是Thread和Object,sleep方法属于Thread类中的静态方法,wait属于Object的成员方法。

2、sleep()是线程类(Thread)的方法,不涉及线程通信,调用时会暂停此线程指定的时间,但监控依然保持,不会释放对象锁,到时间自动恢复;wait()是Object的方法,用于线程间的通信,调用时会放弃对象锁,进入等待队列,待调用notify()/notifyAll()唤醒指定的线程或者所有线程,才进入对象锁定池准备获得对象锁进入运行状态。

3、wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用(使用范围)。

4、sleep()方法必须捕获异常InterruptedException,而wait()\notify()以及notifyAll()不需要捕获异常。


小小收藏家
7楼 · 2020-12-16 13:42

sleep()和wait()都是线程暂停执行的方法。

1、这两个方法来自不同的类分别是Thread和Object,sleep方法属于Thread类中的静态方法,wait属于Object的成员方法。
2、sleep()是线程类(Thread)的方法,不涉及线程通信,调用时会暂停此线程指定的时间,但监控依然保持,不会释放对象锁,到时间自动恢复wait()是Object的方法,用于线程间的通信,调用时会放弃对象锁,进入等待队列,待调用notify()/notifyAll()唤醒指定的线程或者所有线程,才进入对象锁定池准备获得对象锁进入运行状态。
3、wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用(使用范围)。
4、sleep()方法必须捕获异常InterruptedException,而wait()\notify()以及notifyAll()不需要捕获异常。

 

注意:

  sleep方法只让出了CPU,而并不会释放同步资源锁。

  线程执行sleep()方法后会转入阻塞状态。

  sleep()方法指定的时间为线程不会运行的最短时间。因此,sleep()方法不能保证该线程睡眠到期后就开始执行。

  notify的作用相当于叫醒睡着的人,而并不会给他分配任务,就是说notify只是让之前调用wait的线程有权利重新参与线程的调度。


灰机带翅膀
8楼 · 2020-12-20 13:57

结合synchronized,会更好的理解sleep()和wait()这两个方法,当然也就知道了他们的区别了。

sleep()

sleep() 方法是线程类(Thread)的静态方法,让调用线程进入睡眠状态,让出执行机会给其他线程,等到休眠时间结束后,线程进入就绪状态和其他线程一起竞争cpu的执行时间。
因为sleep() 是static静态的方法,他不能改变对象的机锁,当一个synchronized块中调用了sleep() 方法,线程虽然进入休眠,但是对象的机锁没有被释放,其他线程依然无法访问这个对象。

下面用一个例子来演示:

Service类:

public class Service {    public void mSleep(){
        synchronized(this){            
        try{
                System.out.println(" Sleep 。当前时间:"+System.currentTimeMillis());
                Thread.sleep(3*1000);
            }           
             catch(Exception e){
                System.out.println(e);
            }
        }
    }    
    public void mWait(){
        synchronized(this){
            System.out.println(" Wait 。结束时间:"+System.currentTimeMillis());

        }
    }

}

就定义了两个方法, mSleep()方法会让调用线程休眠3秒,mWait() 就打印一句话。两个方法都使用了同步锁。

SleepThread类:

public class SleepThread implements Runnable{

    private Service service;   
    public SleepThread(Service service){        
    this.service = service;
    }    
    public void run(){
        service.mSleep();
    }

}

线程类,用于调用Service 的mSleep方法

WaitThread类:

public class WaitThread implements Runnable{

    private Service service;    
    public WaitThread(Service service){        
    this.service = service;
    }    
    public void run(){
        service.mWait();
    }

}

线程类,用于调用Service 的mWait方法

测试类:

public class Test{    
public static void main(String[] args){

        Service mService = new Service();
        Thread sleepThread = new Thread(new SleepThread(mService));
        Thread waitThread = new Thread(new WaitThread(mService));
        sleepThread.start();
        waitThread.start();
    }
}

创建了一个Service对象并赋值给mService,还创建了两个线程并传入mService,也就是说两个线程启动后,调用的是同一个Service对象的方法。
先看下结果:
这里写图片描述

梳理一下逻辑:

首先sleepThread线程会启动起来,然后在run方法里调用Service对象的mSleep方法,到了同步代码块后,this就是Test类里创建的Service对象mService,sleepThread线程获得了Service对象的锁,之后进入了休眠状态,但并没有释放该Service对象的锁。
这时waitThread线程也启动了起来,调用Service对象的mWait方法,同样到了同步代码块,因为Service对象的锁已经被sleepThread占了,所以waitThread线程只能干等着。
等到sleepThread线程执行完毕(休眠结束)后释放了同步锁,waitThread线程拿到了同步锁,会继续执行,mWait才会被调用。

如果sleepThread释放了机锁的话,waitThread 的任务会马上得到执行。从打印结果可以看出,waitThread 的任务是3秒钟之后才得到执行。

同步锁,锁住的是一个对象。如果一个线程拿到了一个对象的机锁去执行一段同步代码块了,那么其他线程都不能执行这个对象的其他同步代码块。
在这个例子中就是sleepThread线程拿到了service对象的同步锁,进入后休眠,但没有释放机锁,那么waitThread线程是不能执行这个service对象的其他同步代码块的,也就就是不能进入这一段代码

synchronized(this){
            System.out.println(" Wait 。结束时间:"+System.currentTimeMillis());

}

相信现在你已经理解了sleep方法没有释放机锁会带来什么结果了,那么继续wait

wait()

wait()是Object类的方法,当一个线程执行到wait方法时,它就进入到一个和该对象相关的等待池,同时释放对象的机锁,使得其他线程能够访问,可以通过notify,notifyAll方法来唤醒等待的线程

下面修改程序如下所示:

public class Service {    
public void mSleep(){
        synchronized(this){            
        try{
                Thread.sleep(3*1000);                
                this.notifyAll();
                System.out.println(" 唤醒等待 。 结束时间:"+System.currentTimeMillis());
            }            
            catch(Exception e){
                System.out.println(e);
            }
        }
    }    public void mWait(){

        synchronized(this){            
        try{
                System.out.println(" 等待开始 。 当前时间:"+System.currentTimeMillis());                this.wait();
            }
            catch(Exception e){
                System.out.println(e);
            }
        }
    }
}

测试类:

public class Test{    
public static void main(String[] args){
        Service mService = new Service();
        Thread sleepThread = new Thread(new SleepThread(mService));
        Thread waitThread = new Thread(new WaitThread(mService));
        waitThread.start();
        sleepThread.start();
    }
}

同样先看下打印结果
这里写图片描述

这里是先让 waitThread线程启动起来,然后waitThread线程进入等待状态,并释放了Service对象的锁,这时sleepThread也启动了,来到了mSleep方法的同步代码块,因为之前的waitThread线程已经释放了Service对象的机锁,sleepThread可以拿到对象锁,所以mSleep方法是会被马上调用的。然后sleepThread线程就是进入了睡眠状态,等到3秒休眠结束后调用notifyAll()唤醒了waitThread线程。

综上所诉:
sleep() 和 wait() 的区别就是 调用sleep方法的线程不会释放对象锁,而调用wait() 方法会释放对象锁


我的网名不再改
9楼 · 2020-12-26 20:28

1、每个对象都有一个锁来控制同步访问,Synchronized关键字可以和对象的锁交互,来实现同步方法或同步块。sleep()方法正在执行的线程主动让出CPU(然后CPU就可以去执行其他任务),在sleep指定时间后CPU再回到该线程继续往下执行(注意:sleep方法只让出了CPU,而并不会释放同步资源锁!!!);wait()方法则是指当前线程让自己暂时退让出同步资源锁,以便其他正在等待该资源的线程得到该资源进而运行,只有调用了notify()方法,之前调用wait()的线程才会解除wait状态,可以去参与竞争同步资源锁,进而得到执行。(注意:notify的作用相当于叫醒睡着的人,而并不会给他分配任务,就是说notify只是让之前调用wait的线程有权利重新参与线程的调度);

2、sleep()方法可以在任何地方使用;wait()方法则只能在同步方法或同步块中使用;

3、sleep()是线程线程类(Thread)的方法,调用会暂停此线程指定的时间,但监控依然保持,不会释放对象锁,到时间自动恢复;wait()是Object的方法,调用会放弃对象锁,进入等待队列,待调用notify()/notifyAll()唤醒指定的线程或者所有线程,才会进入锁池,不再次获得对象锁才会进入运行状态;

 

举个列子说明:

public class ThreadTest {public static void main(String[] args) {new Thread(new Thread1()).start();try {Thread.sleep(5000);} catch (Exception e) {e.printStackTrace();}new Thread(new Thread2()).start();}public static class Thread1 implements Runnable {@Overridepublic void run() {synchronized (ThreadTest.class) {System.out.println("进入thread1...");System.out.println("thread1是等待...");try {//调用wait()方法,线程会放弃对象锁,进入等待此对象的等待锁定池ThreadTest.class.wait();} catch (Exception e) {e.printStackTrace();}System.out.println("thread1正在进行 ....");System.out.println("thread1结束!!!");}}}private static class Thread2 implements Runnable {@Overridepublic void run() {synchronized (ThreadTest.class) {System.out.println("进入thread2...");System.out.println("thread2是睡眠");//只有针对此对象调用notify()方法后本线程才进入对象锁定池准备获取对象锁进入运行状态。ThreadTest.class.notify();//==================//区别//如果我们把代码:TestD.class.notify();给注释掉,即TestD.class调用了wait()方法,但是没有调用notify()//方法,则线程永远处于挂起状态。}try {//sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,//但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。//在调用sleep()方法的过程中,线程不会释放对象锁。Thread.sleep(5000);} catch (Exception e) {e.printStackTrace();}System.out.println("thread2正在进行....");System.out.println("thread2结束!!!");}}}

 

运行效果:

 

如果注释掉代码:

 ThreadTest.class.notify();

 

 


相关问题推荐

  • 回答 156

    对于每一位才开始接触JAVA的新手来说,先不要管算法和数据结构,大多数简单的程序不需要用到算法和数据结构,所以当你真正需要时再去学习。编程一段时间以后,你就会知道在哪些地方用到他们。这时知道算法的名字并了解它们的功能,然后动手去实践。当我们在去...

  • 回答 93

    2个都很好就业,更关键的是要学得到东西

  • 回答 12
    已采纳

    获取Map集合中所有的key可以通过map集合的keySet()方法获取例如:    Map map = new HashMap();    map.put(xx,xx); //存放数据    //.... 省略    Set set = map.keySet();    //可以通过迭代器进行测试    Iterator iter = set.iter...

  • 回答 56
    已采纳

    不同年龄,不同掌握程度,学历,找工作城市,面试能力这是一个多方面影响的结果,如果是平均值的话,全国平均薪资14k左右

  • 回答 38

    具体学多久,根据自己的学习力,自律性、解决问题能力来决定若系统性学习,跟着讲师的节奏走,大概半年左右,有专业的讲师把课程进行规划,尽心系统学习,有问题,讲师会帮忙解决,学习的效率很高,避免了自学中出现各种问题解决不了,而耽误很多时间,可能会...

  • 回答 23
    已采纳

    (1)idea启动时会有两个快捷方式,安装完后默认生成在桌面的是32位的idea的快捷方式,如果我们使用这个快捷方式运行大项目,一般都会很卡。解决方法是找到idea的安装目录,然后进入bin文件夹,找到名称为idea64的应用程序,右键他生成桌面快捷方式。以后每次...

  • BIO与NIO、AIO的区别2020-05-19 15:59
    回答 4
    已采纳

    IO的方式通常分为几种,同步阻塞的BIO、同步非阻塞的NIO、异步非阻塞的AIO。一、BIO     在JDK1.4出来之前,我们建立网络连接的时候采用BIO模式,需要先在服务端启动一个ServerSocket,然后在客户端启动Socket来对服务端进行通信,默认情况下服务端需要...

  • Java方法的命名规则2021-04-06 19:07
    回答 31

    ava是一种区分字母的大小写的语言,所以我们在定义变量名的时候应该注意区分大小写的使用和一些规范,接下来我们简单的来讲讲Java语言中包、类、变量等的命名规范。(一)Package(包)的命名Package的名字应该都是由一个小写单词组成,例如com、xuetang9、compan...

  • 回答 2

    public class Point {    private int x;    private int y;    public int getX() {        return x;    }    public void setX(int x) {        this.x = x;    }    public int getY() {        return y;    } ...

  • 回答 6

    经典版单例模式public class Singleton {        private static Singleton uniqueInstance;//利用一个静态常量来记录singleton类的唯一实例。     private Singleton() {     }     public static  Singleton getInstance()...

  • 回答 3

    哈希表的长度一般是定长的,在存储数据之前我们应该知道我们存储的数据规模是多大,应该尽可能地避免频繁地让哈希表扩容。但是如果设计的太大,那么就会浪费空间,因为我们跟不用不到那么大的空间来存储我们当前的数据规模;如果设计的太小,那么就会很容易发...

  • 回答 14

    1. DOM(Document Object Model)        DOM是用与平台和语言无关的方式表示XML文档的官方W3C标准。DOM是以层次结构组织的节点或信息片断的集合。这个层次结构允许开发人员在树中寻找特定信息。分析该结构通常需要加载整个文档和构造层次结构,然后才...

  • 回答 19

    1)作用不同: throw用于程序员自行产生并抛出异常; throws用于声明在该方法内抛出了异常2) 使用的位置不同: throw位于方法体内部,可以作为单独语句使用; throws必须跟在方法参数列表的后面,不能单独使用。3)内容不同: throw抛出一个异常对象,且只能是...

  • 回答 11

    基本执行过程如下:1)程序首先执行可能发生异常的try语句块。2)如果try语句没有出现异常则执行完后跳至finally语句块执行;3)如果try语句出现异常,则中断执行并根据发生的异常类型跳至相应的catch语句块执行处理。4)catch语句块可以有多个,分别捕获不同类型...

  • 回答 20

    100-199 用于指定客户端应相应的某些动作。 200-299 用于表示请求成功。 300-399 用于已经移动的文件并且常被包含在定位头信息中指定新的地址信息。 400-499 用于指出客户端的错误。 400 语义有误,当前请求无法被服务器理解。 401 当前请求需要用户验证...

  • 回答 16

    异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误,只要程序设计得没有问题通常就不会发生。受检异常跟程序运行的上下文环境有关,即使程序设计无误,仍然可能因使用的问题而引发。Java编译...

没有解决我的问题,去提问