Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/342.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
Java concurrentHashMap迭代_Java_Concurrency_Synchronized_Concurrenthashmap - Fatal编程技术网

Java concurrentHashMap迭代

Java concurrentHashMap迭代,java,concurrency,synchronized,concurrenthashmap,Java,Concurrency,Synchronized,Concurrenthashmap,我使用的是一个线程,我们称之为MapChecker,它在ConcurrentHashMap的整个生命周期中都在循环 该映射由其他线程填充,并由MapChecker使用迭代器清除 该地图具有以下结构: private volatile Map<MyObject, SynchronizedList<MyOtherObject>> map = new ConcurrentHashMap<>(); //SynchronizedList = Collections.sy

我使用的是一个线程,我们称之为MapChecker,它在ConcurrentHashMap的整个生命周期中都在循环

该映射由其他线程填充,并由MapChecker使用迭代器清除

该地图具有以下结构:

private volatile Map<MyObject, SynchronizedList<MyOtherObject>> map = new ConcurrentHashMap<>();
//SynchronizedList = Collections.syncrhonizedList.
MapChecker必须更新循环中每个键的值。通过从列表中删除元素或删除完整地图条目来进行更新

同步分两步进行:

在地图内添加数据时同步 检索MapChecker内同步的贴图的迭代器时。 这些锁位于mapitself synchronizedmap上

我不想总是在迭代器视图中保存最后更新的值,但我需要确保在下一次迭代中检索所有缺少的值,这一点很重要,因为我不想跳过任何元素。此外,正确更新SynchronizedList也很重要

我的问题是: 我是否可以通过使用这种体系结构确保插入/更新所有条目?有错过什么的风险吗? 如果MapChecker删除一个条目,而另一个线程正在更新该条目,会发生什么情况?ConcurrentHashMap应该会阻止这些操作,所以我希望不会有任何问题

这是MapChecker循环:

while (!isInterrupted()) {

    executeClearingPhases();

    Iterator<Map.Entry<PoolManager, List<PooledObject>>> it = null;
    synchronized (idleInstancesMap) {
        it = idleInstancesMap.entrySet().iterator();
    }

    while (it.hasNext()) {

        Map.Entry<PoolManager, List<PooledObject>> entry = it.next();
        PoolManager poolManager = entry.getKey();

        boolean stop = false;
        while (!stop) {
            //this list is empty very often but it shouldn't, that's the problem I am facing. I need to assure updates visibility.
            List<PooledObject> idlePooledObjects = entry.getValue();
            if (idlePooledObjects.isEmpty()) {

                stop = true;
            } else {

                PooledObject pooledObject = null;
                try {

                    pooledObject = idlePooledObjects.get(0);
                    info(loggingId, " - REMOOOVINNGG:  \"", pooledObject.getClientId(), "\".");
                    PoolingStatus destroyStatus = poolManager.destroyIfExpired(pooledObject);
                    switch (destroyStatus) {

                        case DESTROY:
                            info(loggingId, " - Removed pooled object \"", pooledObject.getClientId(), "\" from pool: \"", poolManager.getClientId(), "\".");
                            idlePooledObjects.remove(0);
                            break;
                        case IDLE:
                            stop = true;
                            break;
                        default:
                            idlePooledObjects.remove(0);
                            break;
                    }
                } catch (@SuppressWarnings("unused") PoolDestroyedException e) {

                    warn(loggingId, " - WARNING: Pooled object \"", pooledObject.getClientId(), "\" skipped, pool: \"", poolManager.getClientId(), "\" has been destroyed.");
                    synchronized(idleInstancesMap) {

                        it.remove();
                    }
                    stop = true;
                } catch (PoolManagementException e) {

                    error(e, loggingId, " - ERROR: Errors occurred during the operation.");
                    idlePooledObjects.remove(0);
                }
            }
        }
    }
    Thread.yield();
}
这是任何其他线程多次调用的方法:

public void addPooledObject(PoolManager poolManager, PooledObject pooledObject) {

        synchronized (idleInstancesMap) {

            List<PooledObject> idleInstances = idleInstancesMap.get(poolManager);
            if (idleInstances == null) {

                idleInstances = Collections.synchronizedList(new LinkedList<PooledObject>());
                idleInstancesMap.put(poolManager, idleInstances);
            }

            idleInstances.add(pooledObject);
        }
    }
谢谢

但我需要确保在下一次迭代中检索到所有缺少的值,这一点很重要,因为我不想跳过任何元素

首先,我认为基于您的解决方案,只要您继续执行MapChecker循环,我认为您将获得地图中的所有项目。我建议您在当前的MapChecker代码之外有一个额外的whiletrue循环


但是根据您的描述,我建议您应该使用队列而不是映射,显然,您的问题需要一个push/pop操作,也许BlockingQueue更适合这里。

多亏PatrickChen的建议,我将PooledObject实例列表移到了每个已经拥有该列表的PoolManager中,因为它以完全同步的方式拥有该池及其内部状态

结果是:

//MapChecker lifecycle
public void run() {

    try {

        while (!isInterrupted()) {

            executeClearingPhases();

            ListIterator<PoolManager> it = null;
            //This really helps. poolManagers is the list of PoolManager instances.
            //It's unlikely that this list will have many elements (maybe not more than 20)
            synchronized (poolManagers) {

                Iterator<PoolManager> originalIt = poolManagers.iterator();

                while (originalIt.hasNext()) {

                    if (originalIt.next().isDestroyed()) {

                        originalIt.remove();
                    }
                }
                //This iterator will contain the current view of the list.
                //It will update on the next iteration.
                it = new LinkedList<PoolManager>(poolManagers).listIterator();
            }

            while (it.hasNext()) {

                PoolManager poolManager = it.next();
                try {
                    //This method will lock on its internal synchronized pool in order to
                    //scan for expired objects.
                    poolManager.destroyExpired();
                } catch (@SuppressWarnings("unused") PoolDestroyedException e) {

                    warn(loggingId, " - WARNING: Pool: \"", poolManager.getClientId(), "\" has been destroyed.");
                    it.remove();
                }
            }
            Thread.yield();
        }
        throw new InterruptedException();
    } catch (@SuppressWarnings("unused") InterruptedException e) {

        started = false;
        Thread.currentThread().interrupt();
        debug(loggingId, " - Pool checker interrupted.");
    }
}
//Method invoked by multiple threads
public void addPooledObject(PoolManager poolManager) {

    synchronized (poolManagers) {

        poolManagers.add(poolManager);
    }
}

为什么地图本身是不稳定的?你不能让它成为最终的吗?你如何在地图上得到一个迭代器?在检索映射的迭代器时,映射未定义迭代器方法,ConcurrentHashMap.synchronized也未定义迭代器方法。你是说整个迭代都在关键部分?或者只是检索迭代器本身?您好@daniu,我正在映射的入口集上使用迭代器。问题是,您将变量映射声明为volatile表明您可能不理解此修饰符的作用。变量映射不应该改变,最好通过声明变量final来证明它没有改变。是的,但问题是我需要为每个PoolManager对象创建一个插入顺序列表。因此,使用队列不是一个选项,因为我可能必须在每个列表中添加新条目或新元素。所有PoolManager都会生成PooledObject,对吗?为什么不将PoolManager信息添加到PoolObject中,这样您就可以只保留一个队列,不需要映射。解决了!根据你的建议,我改变了我的数据结构,现在代码更干净、更有效。谢谢