java - 在非同步块中等待并通知

时间:2012-08-18 23:31:42

标签: java wait notify

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

这是一个有效的代码。我唯一的问题是,我已经读过必须在Synchornized块中使用notify和wait。但是,在以下示例中,wait和notify未在同步块中使用,仍然不会引发错误。

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);
    }
}

1 个答案:

答案 0 :(得分:3)

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);
使用你的no-arg构造函数初始化

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,因此永远不会抛出异常。

要演示,请尝试在suspendme上调用resumemecnthrd1,而不是......: - )

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. 您只需拨打notify中的resumeme,而不是suspendme。 (事实上​​,如果线程处于休眠状态,即notify
  7. ,则suspendme中的InterruptedException可能会意外触发(i % 10) == 0
  8. 您也不希望notify循环中有while (suspended)。您的while循环现在也可以变为if语句。
  9. 如前所述,您需要synchronized (this)围绕调用while
  10. 的代码
  11. 避免在构造函数中执行真正的逻辑,例如thrd.start()
  12. suspend不一定是synchronizedresume也不一定是synchronized;只有waitnotify来电需要它。
  13. 您可以找到正常运行的示例的修改版here