1

嗨,我正在处理 SCJP 转储,但现在我遇到了问题。这是问题:

void waitForSignal(){
   Object obj = new Object();
   synchronized(Thread.currentThread()){
       obj.wait();
       obj.notify();
   }
}

哪个论述是对的?

A. 这段代码可以抛出一个 InterruptedException

B. 这段代码可以抛出一个非法的MonitorStateException

C. 这段代码可以在十分钟后抛出 TimeoutException

D. 颠倒 obj.wait() 和 obj.notify() 的顺序可能会导致该方法正常完成

E. 从另一个线程调用 notify() 或 notifyAll() 可能会导致该方法正常完成

F. 除非将“obj.wait()”替换为“((Thread) obj).wait()”,否则此代码不会编译

我发现在一个转储文件中答案是 A,而在另一个转储文件中答案是 B。任何人都可以得到正确答案并为我提供解释吗?

4

1 回答 1

0

绝对B在这里是正确的。请参阅IllegalMonitorStateException的 API 文档:

抛出以指示线程已尝试在对象的监视器上等待,或通知其他线程在对象的监视器上等待而不拥有指定的监视器。

获取的监视器是当前线程(顺便说一下,API 文档警告不要这样做)。wait 和 notify 方法在 obj 上调用,它们应该在当前线程对象上调用。

A. Object#wait 可以抛出 InterruptedException。是否发生这种情况取决于实现,语言规范说:

设线程 t 为对对象 m 执行等待方法的线程,设 n 为 t 对 m 的未与解锁动作匹配的锁定动作的数量。发生以下操作之一:

  • 如果 n 为零(即线程 t 尚未拥有目标 m 的锁),则抛出 IllegalMonitorStateException。

  • 如果这是一个定时等待且 nanosecs 参数不在 0-999999 范围内或 millisecs 参数为负数,则抛出 IllegalArgumentException。

  • 如果线程 t 被中断,则抛出 InterruptedException 并将 t 的中断状态设置为 false。

  • 否则,将发生以下顺序:(...)

所以没有严格定义首先检查哪些情况。实际上,Oracle 或 IBM JDK 中不会抛出 InterruptedException,而 IllegalMonitorStateException 会。

但是这段代码本身不会导致InterruptedException,需要在线程上调用中断。我用来尝试的代码是:

public class Test implements Runnable {

    public void run() {
        Object obj = new Object();
        Thread.currentThread().interrupt();
        try {
            synchronized(Thread.currentThread()) {
                obj.wait();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new Thread(new Test()).start();
    }
}

所以理论上A可能是正确的。认证测试问题需要相当明确,规范对这一点有点模棱两可让我认为这不是一个很好的测试问题。

C. “TimeoutException”是假的。如果传入超时的等待过期,则该方法正常返回。

D. 颠倒等待和通知调用的顺序无关紧要,它们都有相同的要求。

E. 另一个线程所做的任何事情都不能使该线程正常完成,因为它被写入。

F.方法wait在Object上,不是Thread,不需要强制转换。

鉴于 B 绝对正确,并且它描述了 Java 程序员需要理解的一个重要点,而 A 是基于对规范的模糊争论,如果你只能选择一个答案,我会推荐 B。

于 2015-10-22T17:29:00.357 回答