线程中的wait()和sleep()有什么区别?

我是否理解wait()-ing线程仍然处于运行模式并使用CPU周期,但sleep()-ing不消耗任何CPU周期正确?

为什么我们同时使用wait()和sleep()?

它们的实现在较低级别上有什么不同?


当前回答

一个等待线程可以被另一个调用正在被等待的监视器上的notify线程“唤醒”,而一个睡眠线程则不能。另外,一个wait(和notify)必须发生在monitor对象上同步的块中,而sleep则不会:

Object mon = ...;
synchronized (mon) {
    mon.wait();
} 

此时,当前正在执行的线程等待并释放监视器。另一个线程可以

synchronized (mon) { mon.notify(); }

(在同一个mon对象上)和第一个线程(假设它是在监视器上等待的唯一线程)将被唤醒。

如果有多个线程在监视器上等待,您也可以调用notifyAll—这将唤醒所有线程。但是,只有一个线程能够获取监视器(记住,等待是在同步块中)并继续执行—其他线程将被阻塞,直到它们获得监视器的锁。

另一点是你在对象本身调用wait(即你在对象的监视器上调用wait),而你在线程上调用sleep。

还有一点是,你可以从wait中得到虚假的唤醒(例如,正在等待的线程没有明显的原因就恢复了)。你应该总是等待在某些条件下旋转,如下所示:

synchronized {
    while (!condition) { mon.wait(); }
}

其他回答

sleep()是一个用来保持进程几秒钟或你想要的时间的方法,但如果wait()方法线程处于等待状态,它不会自动返回,直到我们调用notify()或notifyAll()。

主要的区别是wait()释放锁或监视器,而sleep()在等待时不释放任何锁或监视器。Wait用于线程间通信,而sleep通常用于在执行时引入暂停。

thread .sleep()将当前线程发送到“不可运行”状态一段时间。线程保留它获得的监视器——也就是说,如果线程当前在一个同步块或方法中,没有其他线程可以进入这个块或方法。如果另一个线程调用t.interrupt(),它将唤醒正在睡觉的线程。注意,sleep是一个静态方法,这意味着它总是影响当前线程(正在执行sleep方法的线程)。一个常见的错误是调用t.sleep(),其中t是一个不同的线程;即使这样,当前线程也会休眠,而不是t线程。

object.wait()将当前线程发送到“Not Runnable”状态,就像sleep(),但是有一个扭曲。Wait被调用在对象上,而不是线程上;我们称这个对象为“锁对象”。在lock.wait()被调用之前,当前线程必须在锁对象上同步;Wait()然后释放这个锁,并将线程添加到与锁相关的“等待列表”中。稍后,另一个线程可以同步同一锁对象并调用lock.notify()。这将唤醒原始的等待线程。基本上,wait()/notify()类似于sleep()/interrupt(),只是活动线程不需要直接指向睡眠线程,而只需要指向共享锁对象。

synchronized(LOCK) {   
   Thread.sleep(1000); // LOCK is held
}

synchronized(LOCK) {   
   LOCK.wait(); // LOCK is not held
}

让我们对以上几点进行分类:

呼吁:

wait():调用一个对象;当前线程必须同步锁对象。 sleep():在线程上调用;总是当前执行线程。

同步:

wait():同步的多个线程逐个访问同一个对象。 Sleep():当同步的多个线程等待休眠线程的休眠。

持有锁:

Wait():释放锁,让其他对象有机会执行。 Sleep():如果指定超时或有人中断,则保持锁定至少t次。

唤醒条件:

wait():直到调用notify(), notifyAll()从对象 Sleep():直到至少超时或调用interrupt()。

用法:

Sleep():用于时间同步和; Wait():用于多线程同步。

参考:差别睡眠和等待

方法wait(1000)使当前线程休眠一秒。 如果线程接收到notify()或notifyAll()方法调用,那么线程的睡眠时间可能小于1秒。 调用sleep(1000)会导致当前线程休眠1秒。 此外,睡眠线程不持有锁任何资源。但是等待线程可以。

这里wait()将处于等待状态,直到它被另一个线程通知,而sleep()将有一段时间,之后它将自动转移到就绪状态…

从oracle文档页面的wait()方法的对象:

public final void wait()

导致当前线程等待,直到另一个线程调用该对象的notify()方法或notifyAll()方法。换句话说,这个方法的行为就像简单地执行调用wait(0)一样。 当前线程必须拥有该对象的监视器。线程释放该监视器的所有权并等待,直到另一个线程通知等待该对象监视器的线程被唤醒 可能会出现中断和虚假唤醒 此方法只能由该对象的监视器的所有者的线程调用

这个方法抛出

IllegalMonitorStateException -如果当前线程不是对象的监视器的所有者。 InterruptedException——如果任何线程在当前线程等待通知之前或期间中断了当前线程。抛出此异常时,当前线程的中断状态将被清除。

从oracle文档页关于Thread类的sleep()方法:

public static void sleep(long millis)

使当前正在执行的线程休眠(暂时停止执行)指定的毫秒数,这取决于系统计时器和调度器的精度和准确性。 线程不会失去任何监视器的所有权。

这个方法抛出:

IllegalArgumentException -如果millis的值为负 InterruptedException -如果任何线程中断了当前线程。抛出此异常时,当前线程的中断状态将被清除。

其他关键区别:

Wait()是一个非静态方法(实例方法),不同于静态方法sleep()(类方法)。

你是正确的- Sleep()导致线程“睡眠”,CPU将离开并处理其他线程(也称为上下文切换),而我认为Wait保持CPU处理当前线程。

我们两者都有,因为尽管让其他人在你不使用CPU时使用它似乎是明智的,但实际上上下文切换是有开销的——取决于睡眠的时长,在CPU周期中切换线程可能比简单地让你的线程在几毫秒内什么都不做要昂贵得多。

还要注意,睡眠会强制进行上下文切换。

此外——通常情况下控制上下文切换是不可能的——在等待期间,操作系统可能(并且会有更长的等待)选择处理其他线程。