Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/389.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 跟踪映射中的重复插入(多线程环境)_Java_Multithreading_Duplicates_Spring Batch_Concurrenthashmap - Fatal编程技术网

Java 跟踪映射中的重复插入(多线程环境)

Java 跟踪映射中的重复插入(多线程环境),java,multithreading,duplicates,spring-batch,concurrenthashmap,Java,Multithreading,Duplicates,Spring Batch,Concurrenthashmap,我正在寻找一种方法来跟踪在多线程环境中尝试将同一个键插入映射的次数,以便多个线程可以同时读取和更新映射。如果无法轻松跟踪重复的密钥插入尝试,另一种解决方案是在出现重复密钥插入尝试的第一个迹象时终止应用程序 以下用户定义的单例Springbean显示了我的应用程序使用的全局缓存,它是使用多个分区的Spring批处理作业加载的(要加载的每个数据类型一个作业)。多个线程可以同时调用addResultForDataType方法 public class JobResults { private

我正在寻找一种方法来跟踪在多线程环境中尝试将同一个键插入
映射
的次数,以便多个线程可以同时读取和更新
映射
。如果无法轻松跟踪重复的密钥插入尝试,另一种解决方案是在出现重复密钥插入尝试的第一个迹象时终止应用程序

以下用户定义的单例Springbean显示了我的应用程序使用的全局缓存,它是使用多个分区的Spring批处理作业加载的(要加载的每个
数据类型
一个作业)。多个线程可以同时调用
addResultForDataType
方法

public class JobResults {

    private Map<DataType, Map<String, Object>> results;

    public JobResults() {
        results = new ConcurrentHashMap<DataType, Map<String, Object>>();
    }

    public void addResultForDataType(DataType dataType, String uniqueId, Object result) {
        Map<String, Object> dataTypeMap = results.get(dataType);
        if (dataTypeMap == null) {
            synchronized (dataType) {
                dataTypeMap = results.get(dataType);
                if (dataTypeMap == null) {
                    dataTypeMap = new ConcurrentHashMap<String, Object>();
                    results.put(dataType, dataTypeMap);
                }
            }
        }
        dataTypeMap.put(uniqueId, result);
    }

    public Map<String, Object> getResultForDataType(DataType dataType) {
        return results.get(dataType);
    }

}
我意识到statemet
duplicateCount.put(uniqueId,duplicateCount.get(uniqueId)+1)不是隐式线程安全的。为了保证线程安全,我需要使用同步,这会减慢插入速度。如何跟踪重复插入而不影响应用程序的性能。如果跟踪重复插入不容易,我可以在试图覆盖地图中现有条目的第一个迹象时抛出异常


注意我知道
地图
不允许重复键。我想要的是一种跟踪任何此类尝试并停止应用程序的方法,而不是覆盖
映射中的条目

    ConcurrentHashMap<String, AtomicInteger> duplicateCount = new ConcurrentHashMap<String, AtomicInteger>();

因此,如果你在映射中还没有一个计数,你会把1放进去,如果有,你会得到当前的值,并以原子的方式递增它。这应该是线程安全的。

如果要跟踪插入的数量,可以将外部映射类型更改为类似于
map
(或者,如果不使用Apache Commons,只需
map
,其中
整型
值是更新的数量:

DataType key = ...;
Map<Integer, Object> value = ...;
dataTypeMap.compute(key, (k, current) -> {
    if (current == null) {
        /* Initial count is 0 */
        return Pair.of(0, value);
    } else {
        /* Increment count */
        return Pair.of(current.getFirst(), value);
    }));

您是希望避免外部映射上的重复还是内部映射上的重复。一个接一个地使用原子并不能使整个原子成为原子。它要么放入一个值为1的新原子整数,要么递增一个现有的原子整数。它不会同时使用这两个值。我想,您总是可以这样做:final AtomicInteger oldCount=duplicateCount.putIfAbsent(uniqueId,new AtomicInteger(1));如果(oldCount!=null){oldCount.incrementAndGet();}代码中的警告是不存在“之前发生的事件”读取oldCount和执行空检查之间建立了关系。显然,在当前上下文中-这并不重要,但值得调用它。@PeterL语句
final AtomicInteger oldCount=duplicateCount.putIfAbsent(uniqueId,new AtomicInteger(1));
和整个
if
语句都是一个接一个地运行的,而不是一个原子操作。这仍然不能保证线程安全,对吗?另外,这个解决方案对整体的影响是什么performance@Ping,是的,它们一个接一个地运行。但是,因为它使用ConcurrentHashMap和putIfAbsent调用,所以保证所有线程每个uniqueID都获得相同的AtomicInteger实例。由于AtomicInteger.incrementAndGet是线程安全的,因此不会有任何问题。性能影响最小。ConcurrentHashMap非常高效,AtomicInteger非常快,因为它不使用任何同步调用。感谢您的回答;但是,请注意更改
地图的结构
不是一个选项。
final AtomicInteger oldCount = duplicateCount.putIfAbsent(uniqueId, new AtomicInteger(1));
if (oldCount != null) {
    oldCount.incrementAndGet();
}
DataType key = ...;
Map<Integer, Object> value = ...;
dataTypeMap.compute(key, (k, current) -> {
    if (current == null) {
        /* Initial count is 0 */
        return Pair.of(0, value);
    } else {
        /* Increment count */
        return Pair.of(current.getFirst(), value);
    }));
DataType key = ...;
Map<Integer, Object> value = ...;
if (dataTypeMap.computeIfAbsent(key, k -> value)) != null) {
    /* There was already a value */
    throw new IllegalStateException(...);
});