为什么不使用signalAll激活等待线程?

sunde 发布于 2019-03-09 concurrency 最后更新 2019-03-09 14:42 3 浏览

我有2个功能。第一个discoverHosts()向其他计算机发送请求消息。在此之后,它将通过await命令进入睡眠状态。当他接收到响应时,单独的威胁将调用handleMessage()函数。在处理响应之后,他使用notifyAll()让discoderHosts()知道他必须检查是否收到所有响应。 DiscoverHosts()会在他调用该函数时等待。但是,当单独的威胁调用handleMessage()时,当handleMessage调用signalAll()时,discoverHosts()不会唤醒。我调试debuggig时,如果signalAll()被调用,并且是这种情况。我的项目中的其他地方几乎有相同的代码,它可以工作。 你们有没有人知道我忽略了什么?

private final Lock lock = new ReentrantLock();
private final Condition allReceived = lock.newCondition();
private void discoverHosts() throws Exception {
    lock.lock();
    externalNodes = new HashMap<String, NodeAddress>();
    Message msg = new Message(null, "REQUEST_IP");
    logger.debug("Broadcasting ip request, waiting responses");
    channel.send(msg);
    // TODO:Write a time-out
    while (channel.getView().size() - 1 != externalNodes.keySet().size()) {
        logger.debug("Channel: " + (channel.getView().size() - 1));
        logger.debug("Responses: "+ externalNodes.keySet().size());
        allReceived.await();
    }
    logger.debug("All answers received");
    lock.unlock();
}
protected void handleMessage(Message msg) {
    lock.lock();
    if (!((String) msg.getObject()).matches("IP_RESPONSE:[0-9.]*"))
        return;
    logger.debug("Received answer from " + msg.getObject());
    String ip = ((String) msg.getObject()).replaceAll("IP_RESPONSE:", "");
    // externalHostIps.add(ip);
    NodeAddress currentAddress = new NodeAddress(ip, msg.getSrc());
    externalNodes.put(ip, currentAddress);
    logger.debug("Signalling all threads");
    allReceived.signalAll();
    lock.unlock();
    logger.debug("Unlocked");
}
记录器输出:
4372 [main] DEBUG com.conbit.webhackarena.monitor.monitor.Monitor@3b91eb  - Broadcasting ip request, waiting responses
4372 [main] DEBUG com.conbit.webhackarena.monitor.monitor.Monitor@3b91eb  - Channel: 1
4372 [main] DEBUG com.conbit.webhackarena.monitor.monitor.Monitor@3b91eb  - Responses: 0
4394 [Incoming-1,webhackarena,leendert-K53SV-53745] DEBUG com.conbit.webhackarena.monitor.monitor.Monitor@3b91eb  - Received answer from IP_RESPONSE:192.168.1.106
4396 [Incoming-1,webhackarena,leendert-K53SV-53745] DEBUG com.conbit.webhackarena.monitor.monitor.Monitor@3b91eb  - Signalling all threads
4397 [Incoming-1,webhackarena,leendert-K53SV-53745] DEBUG com.conbit.webhackarena.monitor.monitor.Monitor@3b91eb  - Unlocked
已邀请:

psed

赞同来自:

However when the separate threat calls handleMessage(), discoverHosts() doesn't awake when handleMessage calls the signalAll()
我怀疑你有两个不同的类实例,因为Condition allReceivedprivate final,它们实际上并没有处理相同的条件。 如果您尝试调试此(或使用System.out.println调试),请确保两个线程中的包装类实例相同。

svelit

赞同来自:

我认为你的问题就是这一行

if (!((String) msg.getObject()).matches("IP_RESPONSE:[0-9.]*"))
    return;
这意味着在某种情况下你获得锁定并且永远不会释放它。 始终对Lock使用try...finally块以避免此问题。
protected void handleMessage(Message msg) {
    lock.lock();
    try {
        if (!((String) msg.getObject()).matches("IP_RESPONSE:[0-9.]*"))
            return;
        logger.debug("Received answer from " + msg.getObject());
        String ip = ((String) msg.getObject()).replaceAll("IP_RESPONSE:", "");
        // externalHostIps.add(ip);
        NodeAddress currentAddress = new NodeAddress(ip, msg.getSrc());
        externalNodes.put(ip, currentAddress);
        logger.debug("Signalling all threads");
        allReceived.signalAll();
    } finally {
        lock.unlock();
    }
}