迭代队列的concurrentHashMap以查看是否所有队列都为空,而其他线程可能会添加到队列

时间:2017-12-19 22:37:28

标签: java multithreading iterator thread-sleep concurrenthashmap

这是一个非常具体的问题,但是我们已经停留了一段时间,我在网站上搜索了一个答案而且无法找到它(第一次!)。所以我们走了:

我的数据结构是concurrentHashMap。映射中的每个值都是一个ConcurrentLinkedDeque of Actions(这是我写的一个抽象类,由几个动作扩展 - 与问题无关)。队列被昵称为'演员'。

基本程序流程为:

有一系列线程。每个线程遍历哈希映射,查找要执行的操作。如果操作队列为空,则线程将移动到下一个队列。如果它找到一个动作,该线程将从队列中弹出它并执行该动作。只有在完成所有先前的操作后,才会在程序的运行时间内批量提交新操作。

如果所有队列都为空,会发生什么? 我们希望避免忙碌等待,所以如果所有队列都为空,则线程将进入休眠状态。什么时候醒来?我们保留了一个版本监视器,它基本上计算了向该程序添加了多少动作。线程正在这个柜台上睡觉。

提交给计划的新动作 - >版本计数器递增1 - >线程醒来。

我们如何知道所有队列是否都是空的?嗯,这是一个很好的旧方式 - 我们遍历它们并检查“空”'每一次,同时保持一个'AllAllEmpty'布尔值。

所以这是我们有问题的场景:

- 所有队列都是空的。 - 一个线程遍历所有队列,看看它们是否为空。 - 线程已经检查了某个队列后,会向该队列提交一个新操作。

所以发生了什么:线程认为所有队列都是空的,所以他去睡觉了。他错过了“叫醒”的电话。 (版本号增加了一个),因为当时他没有睡觉(但是在队列中迭代)。没有进一步的行动将提交给该计划,因为旧的一批行动尚未完成。线程等待新操作,操作等待线程。死锁。

我们如何避免这种情况?我们认为使用ConcurrentHashMap应该解决这个问题,但显然迭代它们是不安全的。我们根本不允许使用synchronized。我们只是不知道如何解决它。

我意识到随着线程数量的增加,这个问题变得不太可能,但我们需要能够运行少量线程 - 甚至一个。有一个线程,这种情况经常发生。你会推荐什么?

以下是一些相关代码:

            while (!Thread.currentThread().isInterrupted())
            {
                if(actors.isEmpty())
                //if there's no actors, we need to wait until new actor will added to the hash map
                {
                    try {
                        vm.await(vm.getVersion());//waits until the version monitor will be changed
                    }
                    catch (InterruptedException e1) {
                        Thread.currentThread().interrupt();
                    }
                }
                //check if all queues are empty
                boolean isAllEmpty = true;
                Iterator <ConcurrentHashMap.Entry<String, QueuePair>> it2 = actors.entrySet().iterator();
                while (it2.hasNext() && isAllEmpty){
                    if (!it2.next().getValue().queue.isEmpty())
                        isAllEmpty=false;
                }
                if(isAllEmpty)//all actors are empty
                {
                    try {
                        vm.await(vm.getVersion());//waits until the version monitor will be changed
                    }
                    catch (InterruptedException e1) {
                        Thread.currentThread().interrupt();
                    }
                }
                Iterator <ConcurrentHashMap.Entry<String, QueuePair>>it = actors.entrySet().iterator();
                while (it.hasNext())//if there is an available actors queue, execute one of it actions 
                {
                    //irrelevant code that executes the action
                }
            }
        }

        });

感谢您的回答:)

0 个答案:

没有答案