gpt4 book ai didi

java - Java 中使用尽可能少的锁进行并发字节数组访问

转载 作者:行者123 更新时间:2023-11-30 07:08:20 24 4
gpt4 key购买 nike

我正在尝试减少分段数据的锁定对象的内存使用量。查看我的问题 herehere 。或者假设您有一个字节数组,并且每 16 个字节都可以(反)序列化为一个对象。我们称其为行长度为 16 字节的“行”。现在,如果您从编写器线程修改这样的行并从多个线程读取,则需要锁定。如果字节数组大小为 1MB (1024*1024),这意味着 65536 行和相同数量的锁。

这有点太多了,而且我需要更大的字节数组,我想将其减少到与线程数大致成正比的程度。我的想法是创建一个

ConcurrentHashMap<Integer, LockHelper> concurrentMap;

哪里Integer是行索引,在线程“进入”行之前,它会在此映射中放置一个锁对象(从 this answer 得到这个想法)。但无论我怎么想,我都找不到真正线程安全的方法:

// somewhere else where we need to write or read the row
LockHelper lock1 = new LockHelper();
LockHelper lock = concurrentMap.putIfAbsent(rowIndex, lock1);
lock.addWaitingThread(); // is too late
synchronized(lock) {
try {
// read or write row at rowIndex e.g. writing like
bytes[rowIndex/16] = 1;
bytes[rowIndex/16 + 1] = 2;
// ...
} finally {
if(lock.noThreadsWaiting())
concurrentMap.remove(rowIndex);
}
}

您认为有可能使其线程安全吗?

我有一种感觉,这看起来与concurrentMap.compute非常相似。 construct (例如,参见 this answer )或者我什至可以利用这种方法吗?

map.compute(rowIndex, (key, value) -> {
if(value == null)
value = new Object();
synchronized (value) {
// access row
return value;
}
});
map.remove(rowIndex);

因为我们已经知道计算操作是原子的,所以值和“同步”是否有必要?

// null is forbidden so use the key also as the value to avoid creating additional objects
ConcurrentHashMap<Integer, Integer> map = ...;

// now the row access looks really simple:
map.compute(rowIndex, (key, value) -> {
// access row
return key;
});
map.remove(rowIndex);

顺便说一句:从什么时候起我们就用 Java 进行了这种计算。从1.8开始?在 JavaDocs 中找不到此内容

更新:我发现了一个非常相似的问题 here使用 userIds 而不是 rowIndices,请注意,该问题包含一个示例,其中存在多个问题,例如缺少 final ,调用 lock里面try-finally - 条款和缺乏缩小 map 。似乎还有a library JKeyLockManager为此目的,但是 I don't think it is thread-safe .

更新 2:解决方案似乎非常简单,Nicolas Filotto 指出了如何避免删除:

map.compute(rowIndex, (key, value) -> {
// access row
return null;
});

所以这确实是内存消耗较少的,但是使用 synchronized 进行简单的段锁定my scenario 至少快 50% .

最佳答案

Is the value and the synchronized necessary at all as we already know the compute operation is atomically?

我确认不需要添加synchronized在本例中 block 为 compute方法以原子方式完成,如 ConcurrentHashMap#compute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction) 的 Javadoc 中所述。已添加 BiFunctionJava 8 ,我引用:

Attempts to compute a mapping for the specified key and its current mapped value (or null if there is no current mapping). The entire method invocation is performed atomically. Some attempted update operations on this map by other threads may be blocked while computation is in progress, so the computation should be short and simple, and must not attempt to update any other mappings of this Map.

您试图通过 compute 实现什么目标如果你创建 BiFunction ,方法可能是完全原子的总是返回null也以原子方式删除 key ,以便一切都将以原子方式完成。

map.compute(
rowIndex,
(key, value) -> {
// access row here
return null;
}
);

这样您就可以完全依赖 ConcurrentHashMap 的锁定机制。同步您对行的访问。

关于java - Java 中使用尽可能少的锁进行并发字节数组访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39675003/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com