许多线程访问的地图上的准确数据

Accurate data on a map accessed by many threads

我正在尝试根据实例化时赋予对象的权重将对象分为五个独立的组。

现在,我想将这些对象按重量分为五组。为此,必须将每一个与另一个进行比较。

现在我遇到的问题是这些对象被添加到单独的工作线程上的组​​中。每个人都被发送到同步排序功能,在一个对象完成图片下载后,与当前三个组中的所有成员进行比较。

组已设置为两个不同的地图。第一个是 Hashtable,它会导致程序崩溃并抛出未知的 ConcurrencyIssue。当我使用 ConcurrentHashMap 时,数据是错误的,因为它没有在下一个对象与 ConcurrentHashmap 进行比较之前及时删除条目。所以这会导致逻辑错误并产生只有一半时间正确排序的组。

我需要 hashmap 在下一次排序发生之前立即从映射中删除条目...我认为同步函数可以做到这一点,但它似乎仍然不起作用。

是否有更好的方法来对正在由工作线程添加到数据结构的对象进行排序?谢谢!我对这个有点迷茫。

private synchronized void sortingHat(Moment moment) {
    try {
        ConcurrentHashMap[] helperList = {postedOverlays, chanl_2, chanl_3, chanl_4, chanl_5};

        Moment moment1 = moment;

        //Iterate over all channels going from highest channel to lowest
        for (int i = channelCount - 1; i > 0; i--) {

            ConcurrentHashMap<String, Moment> table = helperList[i];

            Set<String> keys = table.keySet();

            boolean mOverlap = false;

            double width = getWidthbyChannel(i);

            //If there is no objects in table, don't bother trying to compare...
            if (!table.isEmpty()) {

                //Iterate over all objects currently in the hashmap
                for (String objId : keys) {
                    Moment moment2 = table.get(objId);

                    //x-Overlap
                    if ((moment2.x + width >= moment1.x - width) ||
                            (moment2.x - width <= moment1.x + width)) {

                        //y-Overlap                           
                        if ((moment2.y + width >= moment1.y - width) ||
                                (moment2.y - width <= moment1.y + width)) {

                            //If there is overlap, only replace the moment with the greater weight.
                            if (moment1.weight >= moment2.weight) {
                                mOverlap = true;
                                table.remove(objId);
                                table.put(moment1.id, moment1);
                            }
                        }
                    }
                }
            }

            //If there is no overlap, add to channel anyway
            if (!mOverlap) {
                table.put(moment1.id, moment1);
            }

        }
    } catch (Exception e) {
        Log.d("SortingHat", e.toString());
    }
}

table.remove(objId) 就是问题所在。 Moment A 被发送到排序函数,没有问题。添加力矩 B,它重叠,与力矩 A 进行比较。如果力矩 B 的重量小于力矩 A,则一切都很好。如果时刻 B 的权重更大并且必须删除 A,那么当时刻 C 得到排序时,时刻 A 仍将与时刻 B 一起在哈希图中。因此这似乎是逻辑错误所在。

您的同步有问题。

您使用的同步将使用 "this" 锁进行同步。你可以这样想象:

public synchronized void foo() { ... }

相同
public void foo() {
    synchronized(this) {
        ....
    }
}

这意味着,在进入之前,当前Thread会尝试获取"this object"作为锁。现在,如果你有一个工作线程,它也有一个同步方法(用于向 table 添加内容),它们不会完全相互排斥。你想要的是,一个线程必须完成他的工作,然后下一个线程才能开始工作。

The first being a Hashtable, which crashes the program throwing an unknown ConcurrencyIssue.

这个问题是因为它可能会发生,即 2 个线程同时调用某些东西。为了说明这一点,假设一个线程在其上调用 put(key, value),而另一个线程调用 remove(key)。如果这些调用同时执行(比如由不同的内核执行),那么生成的 HashTable 会是什么?因为没有人可以肯定地说,ConcurrentModificationException 将被抛出。注意:这是一个非常简单的解释!

When I use a ConcurrentHashMap, the data is wrong because it doesn't remove the entry in time before the next object is compared against the ConcurrentHashmap

ConcurrentHashMap是一个实用工具,为了避免所说的并发问题,它并不神奇,多功能,独角兽狩猎,黄油刀。它使 mehtod 调用同步,这导致了这样一个事实,即只有一个线程可以添加到 HashMap 或从中删除,或者在 HashMap 上执行任何其他工作。它不具有与某种锁相同的功能,这将导致对分配给线程的映射的访问。

可能有一个线程想要调用添加,一个线程想要调用移除。 ConcurrentHashMap 只限制事件中的那些调用,它们不能同时发生。哪个先来?你有权力(在这种情况下)。你想要的是,一个线程必须完成他的工作,然后下一个线程才能完成它的工作。

你真正需要什么取决于你。 java.util.concurrent package 带来了一整套 类 供您使用。例如:

您可以为每个地图使用 lock。这样,每个线程(sorting/removing/adding 或其他)可以首先获取所述 Map 的锁,然后在该 Map 上工作,如下所示:

public Worker implements Runnable {
    private int idOfMap = ...;
    @Override
    public void run() {
        Lock lock = getLock(idOfMap);
        try {
            lock.lock();
            // The work goes here
            //...
        } finally {
            lock.unlock();
        }
    }
}

lock.lock() 行将确保在方法调用 returns 之后没有其他线程当前正在处理 Map 并修改它,因此该线程将具有地图上的相互访问。没有一种排序,在您完成删除正确的元素之前。

当然,您必须以某种方式持有上述锁,就像在数据对象中一样。话虽如此,您还可以在每个线程中使用信号量、同步(映射),或者以 Runnable 的形式在地图上制定您的工作,并将它们传递给另一个线程,该线程会逐一调用他收到的所有 Runnable。可能性几乎是无限的。我个人建议从锁开始。