此Q查找以下内容的验证和/或评论/意见:
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();
}
}
以上是"信令"通过使用notify()
来获得快乐。
另一种方法是管理这个"信令" 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()
和setJoy2()
- 可以看到joy
何时设置并按照预期的方式行事(?)
guardedJoy2()
与guardedJoy()
相比如何?
它实现与guardedJoy()
完全相同的东西 - 我可能会遗漏一些东西,但我没有看到结果的差异。唯一的区别是guardedJoy2()
从循环内释放this
的锁定,而其他人在方法终止之前获取它以获得一些意外结果。将它放在一边(即,假设这是joy
及其副作用在代码中出现的唯一地方),guardedJoy()
和{{1}之间没有区别}(?)
guardedJoy2()
回复guardedJoy2()
和setJoy()
。
它可以听到"从setJoy2()
完成后,重新获得锁并从那里开始。
而且,它可以听到"来自setJoy()
- 通过接收中断并因此抛出setJoy2()
以退出InterruptedException
,这也是同步声明的结束,检查以查看wait()
条件while
已设置并从那里开始。如果中断来自"某人"否则,而不是从一个设置joy
,再次以相同的方式进入循环,直到设置joy
。
何时调用joy
,因此在wait()
中释放了this
的锁定,
一些其他线程可以通过获取此锁来进入并执行在guardedJoy2()
设置并且joy
应该正确返回之前不应该执行的操作。但是,将此放在一边(再次,假设这不是一个问题 - 唯一需要注意的是在控制台的guardedJoy2()
的最后一行看到该消息。)这个 - {{1如果对象在其guardedJoy2()
设置并从那里开始(在setJoy2()
中,线程设置joy
,则可以优先考虑其他事情没有必要让对象锁定来中断它,而setJoy2()
应该有锁定来调用它上面的joy
。
setJoy()
& notifyAll()
与guardedJoy2()
& setJoy2()
以上?
TIA。
答案 0 :(得分:0)
我假设你的第一个notify()
只是setJoy
而不是notifyAll().
首先,需要注意的是,如果您在interrupt()
类型的表达式上调用TheClass
,则TheClass
是{{1}的子类}}。这需要against一些-recommendations,表明您应该使用Thread
实例来封装要在线程上运行的逻辑,而不是继承类Runnable
。 javadoc of Thread#join(int)
也声明了
建议应用程序不要在
Thread
个实例上使用wait
,notify
或notifyAll
。
这是因为Java的某些实现使用这些方法来处理幕后的线程逻辑。如果您不知道该实现逻辑并将这些方法与Thread
实例一起使用,则可能会出现意外行为。
然后,这可能需要进行一些分析,抛出(创建)异常是expensive operation,可能比removing a Thread
from an object's wait set更多。更重要的是,异常应该用于特殊情况,而不是指导您的应用程序逻辑。
我打算说你的第二个示例的同步顺序可能不正确(假设Thread
不是joy
),因为volatile
循环中的读取可能看不到写入guardedJoy2
。但是,Java语言规范说明
如果线程T1中断线程T2,则T1中断 同步 - 任何其他线程(包括T2)的任何一点 确定T2已被中断(通过具有
setJoy2
抛出或调用InterruptedException
或。{Thread.interrupted
)
所以你仍然有可见性保证。