我们有一个使用 Hazelcast Multimap 的用例。我们为集合中的每个元素的每个键生成一个线程。例如,如果 key1 有 10 个值,那么我们将生成 10 个线程,每个线程对应集合中的 10 个元素。
每个线程都尝试以并发方式更新它正在使用的元素。我的问题:
每次线程必须更新元素时,我都需要锁定 key1 吗?
我们有一个现有的系统,当我们必须使用任何键的集合更新任何元素时,我们会锁定 Multimap 键。由于某种原因,当值集合的大小为 30+ 时,我间歇性地遇到一个问题,即某个线程未释放键上的锁,并且后续线程持续等待很长时间(30+ 秒)锁。因此,如果一开始就能安全地摆脱锁定,那就太好了。
这取决于您想做什么。例如,这段代码是线程安全的。
MultiMap<Integer, Integer> multiMap = hazelcastClientInstance.getMultiMap(MULTI_MAP_NAME);
final int numThreads = 1000;
CountDownLatch latch = new CountDownLatch(numThreads);
for (int index = 0; index < numThreads; index++) {
final int value = index;
new Thread(() -> {
multiMap.put(KEY, value);
latch.countDown();
}).start();
}
latch.await();
因为对数据结构的操作是由hazelcast上的单个线程执行的。有多少客户端线程发布操作并不重要
但是这段代码不是线程安全的。因为如文档中所述
同时改变给定 Collection 的结果是 未定义。
MultiMap<Integer, Integer> multiMap = hazelcastClientInstance.getMultiMap(MULTI_MAP_NAME);
multiMap.clear();
multiMap.put(KEY, 0);
final int numThreads = 1000;
CountDownLatch latch = new CountDownLatch(numThreads);
for (int index = 0; index < numThreads; index++) {
new Thread(() -> {
TreeSet<Integer> integerSet = new TreeSet<>(multiMap.get(KEY));
// The clients are working on the collection without a lock
Integer first = integerSet.first();
LOGGER.info("first is {}", first);
Set<Integer> collection = Set.of(first + 1);
try {
multiMap.putAllAsync(KEY, collection).toCompletableFuture().get();
} catch (Exception ignored) {
}
latch.countDown();
}).start();
}
latch.await();
总而言之,如果操作发布键+值,那么它是线程安全的。 如果操作是发布密钥+集合,则操作可能需要在密钥上使用锁