当前位置: 首页 > 知识库问答 >
问题:

安全访问多线程HashMap Java

施阳夏
2023-03-14

我有一个应用程序,它有一个ConcurrentHashMap本地存储一个存储在外部服务器上的数据副本。地图每隔几秒钟就会更新一次数据的新副本。

我有一个循环,每隔几秒钟运行一次,它可以访问HashMap并按照值的顺序将元素添加到数组中(实际上它做的事情还多一些,但这并不相关)。我的问题是,如果数据在创建数组的过程中发生了变化,您可能会在不同的地方有重复的键,或者完全省略一些键。

示例:

// Map starts out like this
1 -> value1
2 -> value2
3 -> value3
4 -> value4

// First 2 elements of array created
value1,value2

// Map is updated
3 -> value3
1 -> value1
2 -> value2
4 -> value4

// Last 2 elements of array created
value1,value2,value1,value4

如您所见,如果未更改映射,则数组将为:“value1,value2,value3,value4”或“value2,value3,value1,value4”(如果在更新后运行)。

这里是一些示例代码,它不是原始代码,但它应该解释我的问题:

Map<Integer, String> mapThatGetsUpdated = new ConcurrentHashMap<Integer, String>();
String[] array = new String[mapThatGetsUpdated.size()];

for (int i = 0; i < mapThatGetsUpdated.size(); i++) {
    array[i] = mapThatGetsUpdated.get(i);
}

很明显的方法是复制地图,然后在使用后丢弃它,但我想要另一种方法,因为地图可能相当大,它将不得不复制,可能一秒钟几次。

共有1个答案

韩季
2023-03-14

这是一个问题,因为虽然concurrenthashMap是线程安全的,但您在执行复合操作时没有锁定。

如果要保证状态一致,就必须防止边读边写。

如果希望读者在整个读操作中看到相同的信息,则必须;

  • 在读取期间防止写入
  • 创建正在开始读取的实体的快照

选项1(不这样做)

在读写过程中使用synchronized锁定映射,允许一次发生一个。

在读取映射之前,请复制该映射。

注意到迭代可能只是在执行html" target="_blank">循环以外的操作,您可以尝试通过只复制synchronized块中的映射并使用副本来最小化读取时的锁。

因为你的阅读是相当有规律的,这很可能也无济于事。

备选方案3

使用AtomicReference。将读取器中的引用复制到本地引用。编写器用一个全新的映射替换引用。

这个选项的可行性取决于有多少写作正在发生。它被称为写即复制,如果写的次数少而读的次数多,则可以获得良好的吞吐量。

备选案文4

请使用ReentranTreadWriteLock。将map更改为hashmap并自己控制并发(编写包装类)。

使用readlock锁定读取,使用writelock锁定写入。您可以有许多读者,但一次只能有一个作者。

 类似资料:
  • 我找到了关于线程安全的代码,但它没有来自给出示例的人的任何解释。我想知道为什么如果我不在“count”之前设置“synchronized”变量,那么count值将是非原子的(总是=200是期望的结果)。谢谢

  • 我得到以下错误与Kafka0.10.1.0和火花2.0.2 例外 allreade看到了邮件链,但还没有解决方案https://www.mail-archive.com/user@火花。阿帕奇。org/msg566。html

  • 问题内容: 我从一个非常简单的多线程示例开始。我试图做一个线程安全的计数器。我想创建两个线程,使计数器间歇地增加到1000。以下代码: 据我所知,while循环现在意味着只有第一个线程才能访问计数器,直到达到1000。输出: 我该如何解决?如何获得共享计数器的线程? 问题答案: 两个线程都可以访问您的变量。 您看到的现象称为线程饥饿。输入代码的受保护部分后(很抱歉,我之前错过了它),其他线程将需要

  • 如果有多个Java线程同时写入同一个套接字实例,这会影响从同一个套接字读取的对象的完整性吗?例如,对象的内容是否会被弄乱等。对象的顺序可以是随机的。

  • When using any of the threaded mpms in Apache 2.0 it is important that every function called from Apache be thread safe. When linking in 3rd party extensions it can be difficult to determine whether t

  • 我是一个新手。我有需要读取Kafka流和过滤数据的要求 这是Spring批处理配置。 并且存在开始新作业的控制器endpoint。这是我必须使用的方式:开始新工作 我已经看到KafkaItemReader不是线程安全的。我想知道这种方法是正确的,还是有任何方法可以在多线程spring批处理环境中读取kafka流。谢谢