wait / notifyAll无法按预期工作

时间:2018-04-26 12:58:36

标签: java multithreading concurrency

我有一个有两种方法的类,一个发送消息,另一个确认消息已被接收/处理

   public void send(OTAHotelAvailRS otaHotelAvailRS) throws Exception {
        MessageAvailRs messageAvailRs = new MessageAvailRs();
        messageMap.put(messageAvailRs.getMessageId(), messageAvailRs);
        synchronized (messageAvailRs) {
            messagesSend++;
            messageAvailRs.wait();
            messageWake++;
        }
    }



 public void confirmMessage(String messageId) {
        logger.debug("Confirmed message: " + messageId);
        MessageAvailRs messageAvailRs = messageMap.remove(messageId);
        if (messageAvailRs != null) {
            synchronized (messageAvailRs) {
                messageAvailRs.notifyAll();
                messagesReceived++;
            }
        }
    }

在多线程安装(3线程x 100 req)中运行时,有些消息不会从通知中唤醒..

例如,一旦发送了所有消息

messageSend = 100
messageRec = 100
messageWake = 98

并且地图的大小为0,没有重复的messageIds。

我缩短了案子。它更复杂。

我有一项服务,每次收到请求时都会调用方法send。此方法(不在代码中)将消息发送到JMS队列,其他服务器接收此消息,处理它们并将响应发送到另一个JMSQueue,然后JMSConsumer读取响应并调用confirm方法。

有什么问题?

2 个答案:

答案 0 :(得分:1)

您错误地使用了wait()

wait方法应该始终采用这样的while循环:

synchronized (obj) {
     while (<condition does not hold>)
         obj.wait();
     ... // Perform action appropriate to condition
 }

假设Thread1和Thread2正在等待。 Thread3调用notifyAll。 Thread1首先唤醒,并消耗这种情况。当涉及到Thread2时,Thread2应该再次检查这个条件,如果不满足,则Thread2应该落入另一个wait

答案 1 :(得分:0)

感谢james large

问题是在wait()之前调用notifyAll()。解决方法是在收到响应时使用boolean to no wait()。

 public void send(OTAHotelAvailRS otaHotelAvailRS) throws Exception {
        MessageAvailRs messageAvailRs = new MessageAvailRs();
        messageMap.put(messageAvailRs.getMessageId(), messageAvailRs);
        synchronized (messageAvailRs) {
            messagesSend++;
            if  (!messageAvailRs.isConfirmed()) {
                messageAvailRs.wait();
            }
            messageWake++;
        }
    }

public void confirmMessage(String messageId) {
        logger.debug("Confirmed message: " + messageId);
        MessageAvailRs messageAvailRs = messageMap.remove(messageId);
        if (messageAvailRs != null) {
            meesageAvailRs.confirm();
            synchronized (messageAvailRs) {               
                messageAvailRs.notifyAll();
                messagesReceived++;
            }
        }
    }

public synchronized boolean isConfirmed() {
   return confimed;
}

public synchronized confirm() {
   cofirmed = true;
}