扫码关注公众号
关于sleep()和wait(),以下描述错误的一项是()
正确答案是D分析:针对此对象的notify方法后获取对象锁并进入就绪状态,而不是运行状态。另外针对此对象的notifyAll方法后也可能获取对象锁并进入就绪状态,而不是运行状态。
sleep和wait方法有什么区别?
共同点:1.他们都是在多线程的环境下,都可以在程序的调用处阻塞指定的毫秒数,并返回。 2.wait()和sleep()都可以通过interrupt()方法打断线程的暂停状态,从而使线程立刻抛出InterruptedException。如果线程A希望立即结束线程B,则可以对线程B对应的Thread实例调用interrupt方法。如果此刻线程B正在wait/sleep/join,则线程B会立刻抛出InterruptedException,在catch(){}中直接return即可安全地结束线程。需要注意的是,InterruptedException是线程自己从内部抛出的,并不是interrupt()方法抛出的。对某一线程调用interrupt()时,如果该线程正在执行普通的代码,那么该线程根本就不会抛出InterruptedException。但是,一旦该线程进入到wait()/sleep()/join()后,就会立刻抛出InterruptedException。不同点:1.每个对象都有一个锁来控制同步访问。Synchronized关键字可以和对象的锁交互,来实现线程的同步。sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。 2.wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用 3.sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常4.sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,给执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。5.wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。
为什么wait要定义在Object中,而不定义在Thread中?
线程为了进入临界区(也就是同步块内),需要获得锁并等待锁可用,它们并不知道也不需要知道哪些线程持有锁,它们只需要知道当前资源是否被占用,是否可以获得锁,所以锁的持有状态应该由同步监视器来获取,而不是线程本身。较详细的解释wait和nofity不是常见的普通java方法或同步工具,在Java中它们更多的是实现两个线程之间的通信机制。如果不能通过类似synchronized这样的Java关键字来实现这种机制,那么Object类中就是定义它们最好的地方,以此来使任何Java对象都可以拥有实现线程通信机制的能力。记住synchronized和wait,notify是两个不同的问题域,并且不要混淆它们的相似或相关性。同步类似竞态条件,是提供线程间互斥和确保Java类的线程安全性的,而wait和notify是两个线程之间的通信机制。另一个原因:每个对象都可以作为锁在Java中,为了进入临界区代码段,线程需要获得锁并且它们等待锁可用,它们不知道哪些线程持有锁而它们只知道锁是由某个线程保持,它们应该等待锁而不是知道哪个线程在同步块内并要求它们释放锁。这个比喻适合等待和通知在object类而不是Java中的线程。
阿里面试题:wait为什么一定要写在同步块中?
第一点:wait会引起lostwakeup问题,就是如果wait和notify写在同一个synchronized对象中话,会出现发送notify的之后,另外一个该对象的才刚刚调用wait方法,这就导致调用wait的对象一直无法被显式唤醒。第二点:这个是自己的想法,因为wait()是Object类型中方法,也就是wait是针对于对象而言,而每个对象都有自己的monitor锁,访问操作这个对象首先要获得monitor锁,而且也由于wait()操作会放弃对cpu的占用,所以想要唤醒某个线程,必要要获取对象的锁,也就是说要获取synchronized,所以wait()和notify()必须要写在同一个对象的synchronized代码块中。