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

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

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

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


当前回答

睡眠/中断和等待/通知之间的一个潜在的巨大区别是

在sleep()期间调用interrupt()总是抛出异常(例如InterruptedException),而 在wait()期间调用notify()不会。

在不需要的时候生成异常是低效的。如果线程之间的通信速率很高,那么如果一直调用interrupt,就会产生很多异常,这完全是浪费CPU。

其他回答

在我看来,这两种机制之间的主要区别在于,睡眠/中断是处理线程的最基本方式,而等待/通知是一种抽象,旨在使线程间的通信更容易。这意味着睡眠/中断可以做任何事情,但这个特定的任务更难完成。

为什么等待/通知更合适?以下是一些个人考虑:

它加强了中央集权。它允许使用单个共享对象协调一组线程之间的通信。这大大简化了工作。 它强制同步。因为它使程序员将等待/通知调用包装在同步块中。 它与线程的起源和编号无关。使用这种方法,您可以任意添加更多线程,而无需编辑其他线程或跟踪现有线程。如果使用sleep/interrupt,首先需要保留对休眠线程的引用,然后手动逐个中断它们。

一个来自现实生活的例子很好地解释了这一点,一个经典的餐厅和员工之间用来沟通的方法:服务员把顾客的要求放在一个中心的地方(一块软木板,一张桌子等),摇铃,然后厨房的工人来接受这些要求。一旦有菜准备好了,厨房工作人员就会再次按铃,让服务员知道并把菜送到顾客面前。

在这里,我列出了wait()和sleep()方法之间的一些重要区别。 PS:也可以点击链接查看库代码(内部工作,只是为了更好地理解而玩一下)。

wait ()

Wait()方法释放锁。 wait()是Object类的方法。 wait()是非静态方法——public final void wait()会抛出InterruptedException{//…} wait()应该由notify()或notifyAll()方法通知。 Wait()方法需要从循环中调用,以处理假警报。 wait()方法必须从同步上下文(即同步方法或块)调用,否则将抛出IllegalMonitorStateException

睡眠()

Sleep()方法不释放锁。 sleep()是java.lang.Thread类的方法。 sleep()是静态方法——public static void sleep(long millis, int nanos)会抛出InterruptedException{//…} 在指定的时间量之后,sleep()将完成。 Sleep()最好不要从循环中调用(即。参见下面的代码)。 Sleep()可以从任何地方调用。没有具体的要求。

参考:等待和睡眠的区别

调用等待和睡眠方法的代码片段

synchronized(monitor){
    while(condition == true){ 
        monitor.wait()  //releases monitor lock
    }

    Thread.sleep(100); //puts current thread on Sleep    
}

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

一个等待线程可以被另一个调用正在被等待的监视器上的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(); }
}

关于睡眠不释放锁,等待释放锁的例子

这里有两个类:

Main:包含Main方法和两个线程。 单例:这是一个单例类,有两个静态方法getInstance()和getInstance(boolean isWait)。 公共类Main { private static singletonA = null; private static Singleton singletonB = null; public static void main(String[] args)抛出InterruptedException { 线程threadA =新线程(){ @Override 公共无效运行(){ singletonA = Singleton.getInstance(true); } }; 线程threadB = new Thread() { @Override 公共无效运行(){ singletonB = Singleton.getInstance(); while (singletonA == null) { system . out。println("SingletonA still null"); } if (singletonA == singletonB) { system . out。println("两个单例是相同的"); }其他{ system . out。println("两个单例不相同"); } } }; threadA.start (); threadB.start (); } }

and

public class Singleton {

    private static Singleton _instance;

    public static Singleton getInstance() {

    if (_instance == null) {
        synchronized (Singleton.class) {
            if (_instance == null)
                _instance = new Singleton();
        }
    }
    return _instance;

}

public static Singleton getInstance(boolean isWait) {

    if (_instance == null) {
        synchronized (Singleton.class) {
            if (_instance == null) {
                if (isWait) {
                    try {
                        // Singleton.class.wait(500);//Using wait
                        Thread.sleep(500);// Using Sleep
                        System.out.println("_instance :"
                                + String.valueOf(_instance));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                _instance = new Singleton();
            }
        }
    }
    return _instance;

 }
}

现在运行这个例子,你会得到以下输出:

_instance :null
Both singleton are same

这里由线程a和线程b创建的单例实例是相同的。这意味着线程b在外面等待,直到线程a释放它的锁。

现在通过注释Thread.sleep(500)来更改Singleton.java;Singleton.class.wait(500);. 这里因为Singleton.class.wait(500);方法threadA将释放所有获取锁并进入“Non Runnable”状态,threadB将获得change进入synchronized块。

现在再运行一次:

SingletonA still null
SingletonA still null
SingletonA still null
_instance :com.omt.sleepwait.Singleton@10c042ab
SingletonA still null
SingletonA still null
SingletonA still null
Both singleton are not same

这里由线程a和线程b创建的单例实例是不一样的,因为线程b得到了进入同步块的变化,500毫秒后,线程a从它的最后一个位置开始,并创建了一个新的单例对象。