Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/393.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
带有while循环和Thread.sleep()的Java同步块_Java_Multithreading_Locking - Fatal编程技术网

带有while循环和Thread.sleep()的Java同步块

带有while循环和Thread.sleep()的Java同步块,java,multithreading,locking,Java,Multithreading,Locking,我想在一个类中同步两个哈希映射。 我维护两个映射的原因是,我将一个任务分派到不同的服务器,并在一个HashMap中维护原始任务对象,同时在另一个HashMap中管理响应状态好的,不管发生了什么,我在task中调用了相同的sendTaskToAllEndpoints方法。TaskIsOnResponses,有效地在while循环中保持锁,直到新调用的任务也结束 我通过创建一个AtomicInteger对象来捕获这个bug,该对象在每次进入synchronized块时递增,当我离开它并将它们封闭在t

我想在一个类中同步两个哈希映射。
我维护两个映射的原因是,我将一个任务分派到不同的服务器,并在一个HashMap中维护原始任务对象,同时在另一个HashMap中管理响应状态好的,不管发生了什么,我在task中调用了相同的sendTaskToAllEndpoints方法。TaskIsOnResponses,有效地在while循环中保持锁,直到新调用的任务也结束

我通过创建一个AtomicInteger对象来捕获这个bug,该对象在每次进入synchronized块时递增,当我离开它并将它们封闭在try finally块中时递减。第一个任务完成后,我观察到AtomicInteger对象没有下降到0,而是在1和2之间上下波动

第一个任务似乎成功结束,因为没有任何东西阻止回调执行,但一旦第一个任务完成,并且调用了task.taskistone,该方法本身就创建了另一个task实例,并调用sendTaskToAllEndpoints,因此阻止了第二个任务的所有回调调用,依此类推,直到他们以暂停结束


谢谢大家的建议。

您的同步代码看起来不错,不过您不需要在taskMap上进行同步,因为只有一个线程会更改它。此外,如果你把事情搞砸了,拥有依赖于获取多个锁的同步逻辑是一种容易导致死锁的方法;您的目标应该是在仍然保持线程安全的情况下,拥有更少而不是更多的锁定对象。您确定没有其他未发布的代码正在获取任何对象上的锁吗?isTaskOver是公共的,但不是线程安全的!你应该换成私人的。顺便说一句,使用循环+Thread.sleep避免活动等待。最好使用条件等待+notifyAll。我为使其工作所做的唯一更改是删除while循环中的同步块。这意味着阻止我的另一个线程运行的唯一东西是while循环中的同步块。我知道在C语言中,编译器可能为了优化程序,影响多线程程序的功能。Java中也有类似的东西吗?
HashMap<String, Map<InetAddress, TaskResponse>> taskResponseMap = new HashMap<>();
HashMap<String, Task> taskMap = new HashMap<>();

public void endpointHasRespondedCallback(TaskResponse taskResponse, InetAddress from) {
    // Callback threads gets blocked here!
    synchronized(taskResponseMap) {
        synchronized (taskMap) {
            Map<InetAddress, TaskResponse> taskResponses = taskResponseMap.get(taskResponse.taskUuid);
            if (taskResponses == null || !taskResponses.containsKey(from)) {
                // The response does not exists probably due to timeout
                return;
            }
            taskResponses.put(from, taskResponse);
        }
    }
}

public void sendTaskToAllEndpoints(Task task) {
    long taskStartedAt = System.currentTimeMillis();
    HashMap<InetAddress, TaskResponse> taskResponses = new HashMap<>();
    taskResponseMap.put(task.taskUuid, taskResponses);
    taskMap.put(task.taskUuid, task);

    for (InetAddress dest : getDestinationNodes()) {
        sendTaskTo(dest, task);
        messageResponses.put(dest, TaskResponse.emptyTaskResponse());
    }

    // Should wait for response to comeback till the timeout is over
    while (System.currentTimeMillis() < taskStartedAt + timeoutInMillis) {
        Thread.sleep(1000);

        synchronized(taskResponseMap) {
            synchronized (taskMap) {
                if(isTaskOver(task.taskUuid)) {
                    Map<InetAddress, TaskResponse> responses = taskResponseMap.remove(task.taskUuid);
                    taskMap.remove(task.taskUuid);

                    task.taskIsDone(responses);
                    return;
                }
            }
        }
    }

    // If the task is still sitting there, then it must have timed out!
    synchronized(taskResponseMap) {
        synchronized (taskMap) {
            taskResponseMap.remove(task.taskUuid);
            taskMap.remove(task.taskUuid);
        }
    }
}

// Do not synchronize purposefully since it is only being called in synchronized methods
public boolean isTaskOver(String taskUuid) {
    Task task = taskMap.get(taskUuid);
    if (task == null || !taskResponseMap.containsKey(task.taskUuid)) {
        return true;
    } else {
        for (TaskResponse value : taskResponseMap.get(task.taskUuid).values()) {
            if (value.status != TaskResponseStatus.SUCCESSFUL) {
                return false;
            }
        }
    }
    return true;
}