2014-10-05 12 views
2

这种问答寻找验证和/或评论/意见以下:保护块 - notifyAll的()与中断()

的例子上Guarded Blocks如下:

public synchronized void guardedJoy() { 
    // This guard only loops once for each special event, which may not 
    // be the event we're waiting for. 
    while(!joy) { 
     try { 
      wait(); 
     } catch (InterruptedException e) {} 
    } 
    System.out.println("Joy and efficiency have been achieved!"); 
} 

的另一端这个代码 - 一个设置joy正确是这样的:

public void setJoy2(TheClass t) { 
    synchronized (t) { 
     t.joy = true; 
     t.notifyAll(); 
    } 
} 

上面并在通过使用的喜悦“信号”。

一个替代方案是管理这一“信号”通过interrupt()

public void guardedJoy2() { 
    // This guard only loops once for each special event, which may not 
    // be the event we're waiting for. 

    while(!joy) { 
     synchronized(this) { 
      try { 
       wait(); 
      } catch (InterruptedException e) {} 
     } 
    } 
    System.out.println("Joy and efficiency have been achieved!"); 
} 

和一个设置joy,让线程等待它是:

public void setJoy2(TheClass t) { 
    t.joy = true; 
    t.interrupt(); 
} 

我期待作两者之间的比较 - setJoy()setJoy2()

首先,guardedJoy2()上面可以“听到”既setJoy()joy设置setJoy2() properly--可以看到和行为预期的方式(?) 如何guardedJoy2()比较guardedJoy()? 它实现的效果与guardedJoy()完全相同 - 我可能会错过某些东西,但我在结果中看不到差异。唯一的区别是guardedJoy2()从循环中释放了this的锁定,并且其他人在方法终止以获取一些意外结果之前获取它。设置,预留(即,假设这就是利用joy及其带来的副作用出现在代码中的唯一的地方),有没有guardedJoy()guardedJoy2()(?)之间的差异

guardedJoy2()既响应setJoy()setJoy2()。 它可以从setJoy()“听到”它完成时,重新获得它的锁并从那里去。 而且,它可以从setJoy2()“听到” - 接收中断并因此投掷InterruptedException以脱离wait(),这也是同步陈述的结尾,检查在while中查看条件joy已设置并从那里开始。如果中断来自其他人,而不是来自一个设置joy,则以相同方式再次进入循环,直到设置了joy

时,wait()被调用,因而this锁在guardedJoy2(), 释放一些其他的线程可以通过获得这个锁进来时,做到这一点是不应该的事拖到joy设置和guardedJoy2()是应该的事情正确地返回。然而,把它放在一边(再次,假设这不是问题 - 唯一要查找的是在控制台上最后一行guardedJoy2()上看到这条消息。) - setJoy2()可能更适合在其他事情可以在对象上完成joy设置并从那里进行的情况下(在setJoy2()中,线程设置joy不必锁定对象的中断而setJoy()应该有这个锁来调用notifyAll()就可以了)。

如何guardedJoy2() & setJoy2()比较上述guardedJoy() & setJoy()

TIA。

回答

0

我会是你的意思只是notify()在你第一次setJoy而不是​​

首先假设的,一定要注意,如果你在TheClass类型的表达式调用interrupt(),然后TheClass是很重要Thread的子类。这是against-recommendations的数量,它声明您应该使用Runnable实例来封装要在线程上运行的逻辑,而不是对类Thread进行子类化。该javadoc of Thread#join(int)还指出

建议应用程序不使用waitnotify,或notifyAllThread实例。

这是因为Java的某些实现使用这些方法来处理幕后的线程逻辑。如果您不知道该实现逻辑并将这些方法与Thread实例一起使用,则可能会出现意外行为。

然后,这可能需要一些分析,抛出(创建)异常是expensive operation,可能比removing a Thread from an object's wait set更多。更重要的是,异常应该用于特殊情况,而不是指导你的应用逻辑。

我会说,你的第二个例子中的同步顺序可能是不正确的(假设joy没有volatile),因为在guardedJoy2循环读取可能看不到setJoy2写。然而,Java语言规范规定

如果线程T1中断线程T2,由T1 中断同步-与任何点处的任何其他线程(包括T2) 确定T2已经被中断(由具有一个 InterruptedException抛出或通过调用Thread.interruptedThread.isInterrupted

所以,你仍然有知名度的保证到位。