【问题标题】:Java calling Object.notify() before Object.wait() [duplicate]Java 在 Object.wait() 之前调用 Object.notify() [重复]
【发布时间】:2013-11-08 11:12:09
【问题描述】:

我有 2 个线程,一个用于传输,一个用于重播 只有当我在 RXThread 上收到一条消息时,我才想发送一条消息。我使用了 wait() 和 notify(),并且为了防止在 wait() 之前出现通知,我这样做了,但它只在调试中运行时才有效,尽管 RX 线程不发送消息。

private boolean stopped = false;


class StubTxtask implements Runnable {

    public void run() {
        try {

            // Sends all messages in sequence
            for (int i=0; i<txMsgSeq.getMessagesCount(); i++) {
            }
                if (syncRxTx) {
                    synchronized (syncObj) {
                        while(!stopped) {
                            syncObj.wait();
                    }
                    }

                }
                System.out.println("************ "+ i + "/" + txMsgSeq.getMessagesCount());
                pcs.sendMsg((GeneratedMessage)txMsgSeq.getMessage(i));
                if (!syncRxTx) {
                    Thread.sleep(1000);
                }
            }

        } catch (Exception e) {

        }
    }
}


class StubRxtask implements Runnable {

    public void run() {
        while (true) {
            try {
                // Wait for a message() 
                TncMessage msg = (TncMessage) pcs.waitMsg(connInt);
                System.out.println(msg.toString());
                // Add the message to the RX Sequence
                rxMsgSeq.addMessage(msg);

                System.out.println(rxMsgSeq.getMessagesCount());

                if (syncRxTx) {
                    TncHeader header;
                    Method invokeGetHeader;
                    try {
                        invokeGetHeader = msg.getClass().getMethod("getHeader", null);
                        header = (TncHeader) invokeGetHeader.invoke(msg, null);
                        if (header.getType() != EnumMessageType.ACK) {
                            synchronized (syncObj) {
                                stopped = true;
                                syncObj.notify();
                            }

                        }


                    } catch (Exception e) {
                        System.err.println("ERROR - Impossible to find or invoke getHeader() method on msg");
                    }


                }
                stopped = false;

            } catch (Exception e) {

            }
        }
    }
}

【问题讨论】:

    标签: java multithreading concurrency wait


    【解决方案1】:

    如果只能在调试时正常工作,这通常是因为时序问题,这在调试模式下是不同的。

    据我了解您的代码,使用 Phaser 将满足您的要求。移相器就像一个屏障:它导致所有线程等待,直到所有线程都在等待它,除了它是可重用的。由于现在两个线程都在等待另一个线程到达,因此您不再需要 stopped 构造或同步(全部由 Phaser 内部处理)。

    替换

    if (syncRxTx) {
      synchronized (syncObj) {
        while(!stopped) {
          syncObj.wait();
        }
      }
    }
    

    if (syncRxTx) {
      phaser.arriveAndAwaitAdvance();
    }
    

    if (header.getType() != EnumMessageType.ACK) {
      synchronized (syncObj) {
        stopped = true;
        syncObj.notify();
      }
    }
    

    if (header.getType() != EnumMessageType.ACK) {
      phaser.arriveAndAwaitAdvance();
    }
    

    注意:与同步对象一样,Phaser 应声明为 final。

    【讨论】:

      【解决方案2】:

      改为使用 Semaphore 进行同步,因为这类锁处理“提前通知”。

      Semaphore sem = new Semaphore(0);
      
      runConsume() {
        .. sem.aquire(1); // will block if nothing avaiable
      }
      
      runProduce() {
      
        // receivedMessage
        .. sem.release(1);
      }
      

      【讨论】:

        【解决方案3】:

        如果您在另一个线程中的while 循环中使用变量并想要获取新数据,则必须使用volatile 声明它(检查visibility 规则)

        【讨论】:

          猜你喜欢
          • 2011-09-28
          • 2012-05-28
          • 2021-09-17
          • 1970-01-01
          • 2019-01-16
          • 1970-01-01
          • 2019-07-11
          • 2012-12-06
          • 2014-02-19
          相关资源
          最近更新 更多