Java wait()和sleep()的区别

导读

  • 移动开发知识体系总章(Java基础、Android、Flutter)
  • wait()和sleep()的区别
  • 说一下为什么使用wait()方法时,一般是需要while循环而不是if?
  • yield()和join()
  • 注意事项

wait()和sleep()的区别

  • sleep()方法是属于Thread类,wait()方法是属于Object类
  • 调用 sleep()方法,线程不会释放对象锁。而调用 wait() 方法线程会释放对象锁

    sleep()方法是让线程休眠指定的时间,单位毫秒,让出cpu给其他线程,但它的监控状态依然保持着,指定时间到了自动恢复sleep()前的状态。在sleep()过程中线程不会释放对象锁。谁调用sleep()谁睡眠,在A线程中调用B线程的sleep()方法,是A线程去睡眠。
    wait()方法只能从同步块中调用,线程会放弃对象锁,让其他线程可以获得对象锁。
    如果直接调用 wait ()会抛出 java.lang.IllegalMonitorStateException 异常,原因是还没有得到对象锁,所以无法释放锁。

  • sleep()睡眠后不出让系统资源,wait()让其他线程可以占用 CPU
  • sleep(millionseconds)需要指定一个睡眠时间,时间一到会自然唤醒。而wait()需要配合notify()或者notifyAll()使用。
  • sleep()方法需要抛异常,wait()方法不需要

    sleep()方法是单线程的,没有释放锁,这个锁指的是线程锁,不是对象锁,而wait()方法释放锁,这个锁是对象锁,所以sleep()时间到和wait等到notify()之后享受的待遇一样,都是回到就绪状态,等待系统分配cpu.
    sleep(1000)意思是在未来的1000毫秒内本线程不参与CPU竞争,1000毫秒过去之后,这时候也许另外一个线程正在使用CPU,那么这时候操作系统是不会重新分配CPU的,直到那个线程挂起或结束,即使这个时候恰巧轮到操作系统进行CPU 分配,那么当前线程也不一定就是总优先级最高的那个,CPU还是可能被其他线程抢占去。另外值得一提的是Thread.Sleep(0)的作用,就是触发操作系统立刻重新进行一次CPU竞争,竞争的结果也许是当前线程仍然获得CPU控制权,也许会换成别的线程获得CPU控制权。
    wait(1000)表示将锁释放1000毫秒,到时间后如果锁没有被其他线程占用,则再次得到锁,然后wait方法结束,执行后面的代码,如果锁被其他线程占用,则等待其他线程释放锁。注意,设置了超时时间的wait方法一旦过了超时时间,并不需要其他线程执行notify也能自动解除阻塞,但是如果没设置超时时间的wait方法必须等待其他线程执行notify。

说一下为什么使用wait()方法时,一般是需要while循环而不是if?

while(!执行条件) {
    wait();
}
if(!执行条件) {
    wait();
}

举个例子:
while去水果店买苹果,没有了,然后while就和水果店老板说,有水果的时候通知我,我先回去了。if也去水果店买苹果,没有了,然后if就和水果店老板说,有水果的时候通知我,我先回去了。过一段时间,水果店老板发短信告诉while和if,有水果了,while去一看,水果店只是进了香蕉,并不是苹果,所以不是想要的水果,于是回去继续等水果店老板通知,而if根本就不看是不是自己想要的苹果,直接就叫老板送10斤水果过来,这样会导致你得到错误的结果。

while会一直执行循环,直到条件满足,执行条件才会继续往下执行。if只会执行一次判断条件,不满足就会等待。这样就会出现问题。

我们知道用notify() 和notifyAll()可以唤醒线程,一般我们常用的是notifyAll(),因为notify(),只会随机唤醒一个睡眠线程,并不一定是我们想要唤醒的线程。如果使用的是notifyAll(),唤醒所有的线程,那你怎么知道他想唤醒的是某个正在等待的wait()线程呢,如果用while()方法,就会再次判断条件是不是成立,满足执行条件了,就会接着执行,而if会直接唤醒wait()方法,继续往下执行,根本不管这个notifyAll()是不是想唤醒的是自己还是别人,可能此时if的条件根本没成立。

yield()和join()

**yield方法 **
暂停当前正在执行的线程对象。 yield()方法是停止当前线程,让同等优先权的线程或更高优先级的线程有执行的机会。如果没有的话,那么yield()方法将不会起作用,并且由可执行状态后马上又被执行。

join方法
是用于在某一个线程的执行过程中调用另一个线程执行,等到被调用的线程执行结束后,再继续执行当前线程。如:t.join();//主要用于等待t线程运行结束,若无此句,main则会执行完毕,导致结果不可预测。

注意事项

  • 调用wait方法和notify、notifyAll方法前必须获得对象锁,也就是必须写在synchronized(锁对象){......}代码块中。
  • 当线程print1调用了wait方法后就释放了对象锁,否则其他线程无法获得对象锁,也就无法唤醒线程print1。
  • 当this.wait()方法返回后,线程必须再次获得对象锁后才能继续执行。
  • 如果另外两个线程都在wait,则正在执行的线程调用notify方法只能唤醒一个正在wait的线程(公平竞争,由JVM决定)。
  • 当使用notifyAll方法后,所有wait状态的线程都会被唤醒,但是只有一个线程能获得锁对象,必须执行完while(condition){this.wait();}后才能获得对象锁。其余的需要等待该获得对象锁的线程执行完释放对象锁后才能继续执行。
  • 当某个线程调用notifyAll方法后,虽然其他线程被唤醒了,但是该线程依然持有着对象锁,必须等该同步代码块执行完(右大括号结束)后才算正式释放了锁对象,另外两个线程才有机会执行。

文献
https://www.jianshu.com/p/0b6da419b752
https://www.cnblogs.com/loren-Yang/p/7538482.html

你可能感兴趣的:(Java wait()和sleep()的区别)