为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

繁华开满天机 2021-08-25 15:31:48
我试图根据实例化时赋予它们的权重将对象分为五个单独的组。现在,我想根据它们的权重将这些对象分为五组。为了做到这一点,必须将每一个都与另一个进行比较。现在我遇到的问题是这些对象被添加到单独的工作线程上的组中。在对象完成下载图片后,每个都被发送到同步排序功能,该功能与当前在三个组中的所有成员进行比较。这些组已被设置为两个不同的地图。第一个是 Hashtable,它会导致程序崩溃并抛出未知的 ConcurrencyIssue。当我使用 ConcurrentHashMap 时,数据是错误的,因为它在下一个对象与 ConcurrentHashmap 进行比较之前没有及时删除条目。因此,这会导致逻辑错误并产生仅在一半时间内正确排序的组。我需要哈希图在下一次排序发生之前立即从地图中删除条目......我认为同步函数可以做到这一点,但它似乎仍然不起作用。是否有更好的方法来对由工作线程添加到数据结构中的对象进行排序?谢谢!我对这个有点迷茫。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)) {                            }                        }                    }                }            }这table.remove(objId)就是问题发生的地方。时刻 A 被发送到排序功能,并且没有问题。添加时刻 B,它重叠,与时刻 A 进行比较。如果时刻 B 的权重小于时刻 A,则一切正常。如果时刻 B 的权重更大并且 A 必须被移除,那么当时刻 C 被排序时,时刻 A 仍将与时刻 B 一起出现在哈希图中。 所以这似乎是逻辑错误所在。
查看完整描述

1 回答

?
慕后森

TA贡献1802条经验 获得超5个赞

您的同步有问题。


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


public synchronized void foo() { ... }

是相同的


public void foo() {

    synchronized(this) {

        ....

    }

}

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


第一个是 Hashtable,它会导致程序崩溃并抛出未知的 ConcurrencyIssue。


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


当我使用 ConcurrentHashMap 时,数据是错误的,因为它没有在下一个对象与 ConcurrentHashmap 进行比较之前及时删除条目


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


可能有一个想要调用 add 的线程和一个想要调用 remove 的线程。ConcurrentHashMap 仅限制了这些调用,它们不能同时发生。哪个先来?你有权力(在这种情况下)。你想要的是,一个线程必须完成他的工作,然后下一个线程才能完成它的工作。


你真正需要什么取决于你。在java.util.concurrent包带来的,你可以使用类整体阿森纳。例如:


您可以为每个 Map使用一个锁。有了这个,每个线程(排序/删除/添加或其他)可以首先获取所述 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() 将确保在方法调用返回后没有其他线程正在处理 Map 并修改它,因此该线程将具有对 Map 的双向访问权。在您完成删除正确的元素之前,没有一种排序。


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


查看完整回答
反对 回复 2021-08-25
  • 1 回答
  • 0 关注
  • 157 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信