【问题标题】:java - wait and notify in a non-synchronized blockjava - 在非同步块中等待并通知
【发布时间】:2012-08-18 23:31:42
【问题描述】:

抱歉我的格式不正确。我正在使用记事本编写程序。

这是一个有效的代码。我唯一的问题是,我已经读过必须在同步块中使用通知和等待。但是,在下面的示例中,在同步块中没有使用等待和通知,并且仍然没有抛出错误。

class counthrd implements Runnable {

    Thread thrd;
    String x;
    counthrd cnt1;

    counthrd() {
    }
    boolean suspended;
    boolean stopped;

    counthrd(String s, counthrd cnt1) {
        thrd = new Thread(this, s);
        this.cnt1 = cnt1;
        thrd.start();
        x = s;
    }

    public void run() {

        try {
            System.out.println("Starting " + thrd.currentThread().getName());
            for (int i = 1; i < 100; i++) {
                System.out.print(i + "  ");
                if ((i % 10) == 0) {
                    System.out.println();
                    Thread.sleep(500);
                }
//synchronized(cnt1){
                while (suspended) {
                    System.out.println("going to wait mode");
                    wait();
                    notify();
                }
//}
            }
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    synchronized void suspendme() {
        suspended = true;
        notify();
    }

    synchronized void resumeme() {
        suspended = false;
        notify();
    }
}

class counter {

    public static void main(String args[]) throws InterruptedException {
        counthrd cnt1 = new counthrd();
        counthrd cnthrd1 = new counthrd("thrd 1", cnt1);

        Thread.sleep(1000);
        System.out.println("going to wait mode");
        cnt1.suspendme();
        Thread.sleep(1000);
        System.out.println("resuming");
        cnt1.resumeme();
        Thread.sleep(1000);
    }
}

【问题讨论】:

  • 这对你有用吗?通常,wait() 不需要锁定,而 notify() 则需要。
  • 您知道,Eclipse 是免费的。它使您可以键入变量名称的第一部分并提出其余部分。这使您的生活更轻松,并允许您使用名称与 "thrd" 不同的变量。它还为您进行格式化。
  • 那么为什么我的问题被降级了?这是一个真正的问题。
  • 根据§17.2.1 of the Java Language Specification,如果线程对wait 的主题缺少锁定,则会抛出IllegalMonitorStateException
  • @veer “答案是他从来没有真正打电话给wait。”所以发布。

标签: java wait notify


【解决方案1】:

my comment。由于永远不会抛出 IllegalMonitorStateException,因此我们知道永远不会调用 wait

请注意,您有两个 counthrd...

counthrd cnt1 = new counthrd();
counthrd cnthrd1 = new counthrd("thrd 1", cnt1);

查看您在哪个实例上调用suspendmeresumeme

Thread.sleep(1000);
System.out.println("going to wait mode");
cnt1.suspendme();
Thread.sleep(1000);
System.out.println("resuming");
cnt1.resumeme();
Thread.sleep(1000);

cnt1 使用您的无参数构造函数进行初始化,如下所示:

counthrd() {
}

关键是cnt1 从未真正启动它自己的线程。它从不做任何事情,真的。 cnthrd1 是启动线程的那个,如下所示:

counthrd(String s, counthrd cnt1) {
    thrd = new Thread(this, s);
    this.cnt1 = cnt1;
    thrd.start();
    x = s;
}

要说明的一点是suspended 是一个实例字段,而不是在cnt1cnthrd1 之间共享。修改cnt1.suspended 不会导致cnthrd1 进入“等待模式”。 wait 永远不会被调用,因此永远不会抛出异常。

为了演示,请尝试在cnthrd1 上调用suspendmeresumeme,而不是... :-)

C:\dev\scrap>javac counter.java

C:\dev\scrap>java counter
Starting thrd 1
1  2  3  4  5  6  7  8  9  10
11  12  13  14  15  16  17  18  19  20
going to wait mode
going to wait mode
java.lang.IllegalMonitorStateException
resuming

话虽如此,我想我会建议你做一些你的代码应该做的事情。

  1. suspended 声明为volatile。如果没有一些显式的内存排序保证,则无法保证cnthrd1 何时甚至如果 读取suspended 的更新值。
  2. 放弃cnt1 字段和实例;他们没有理由。也摆脱那个空的构造函数。
  3. Thread.currentThread 是静态方法;您不需要为此使用实例。除此之外,thrd 在这里保证等于 Thread.currentThread
  4. counthrd.x 等于 thrd.getName;为什么不直接使用x
  5. 使用更好、更具描述性的名称。例如,为什么不用x 而不是name?为什么不用thrd 而不是thread?为什么不用counthrd 而不是CountingThread
  6. 您只需要在resumeme 中调用notify,而不是suspendme。 (事实上​​,在suspendme 中调用notify 可能会在线程处于休眠状态时意外触发InterruptedException,即当(i % 10) == 0 时)
  7. 您也不希望notifywhile (suspended) 循环中。现在,您的 while 循环实际上也可以转换为 if 语句。
  8. 如前所述,您需要在调用 while 的代码周围使用 synchronized (this)
  9. 避免在构造函数中执行真正的逻辑,例如thrd.start()
  10. suspend 不需要是 synchronizedresume 也不需要是 synchronized;只有waitnotify 调用需要它。

您可以找到可以正常工作的示例的修改版本here

【讨论】:

  • @veer...非常感谢您抽出宝贵时间详细解释。我实际上想在counthrd 上创建 2 个线程来交错输出,并且我想要这 2 个线程使用的通用参考。所以这就是我试图创建cnt1 实例的原因。同样在同步块中,我想在这个公共引用cnt1 上同步,而不是在this 上同步每个线程的实例。无论如何,我发现无论我想做什么疯狂的事情,我仍然需要在同步块中使用this。我也看了修改后的版本。再次感谢。
猜你喜欢
  • 1970-01-01
  • 2023-03-27
  • 2015-01-26
  • 1970-01-01
  • 1970-01-01
  • 2017-09-16
  • 2015-11-12
  • 2019-12-23
  • 1970-01-01
相关资源
最近更新 更多