java - ConcurrentHashMap.computeIfAbsent 中的赋值是线程安全的吗?

标签 java thread-safety

考虑以下某种固定大小缓存的实现,它允许通过整数句柄进行查找:

static class HandleCache {
    private final AtomicInteger counter = new AtomicInteger();
    private final Map<Data, Integer> handles = new ConcurrentHashMap<>();
    private final Data[] array = new Data[100_000];

    int getHandle(Data data) {
        return handles.computeIfAbsent(data, k -> {
            int i = counter.getAndIncrement();
            if (i >= array.length) {
                throw new IllegalStateException("array overflow");
            }
            array[i] = data;
            return i;
        });

    }

    Data getData(int handle) {
        return array[handle];
    }
}

计算函数内部有一个数组存储,它不以任何方式同步。 Java 内存模型是否允许其他线程稍后从该数组读取空值?

PS:如果从 getHandle 返回的 id 存储在 final 字段中并且只能通过该字段从其他字段访问,结果会改变吗线程?

最佳答案

读取访问不是线程安全的。您可以间接使其线程安全,但它可能很脆弱。我会以更简单的方式实现它,并且只有在它被证明存在性能问题时才对其进行优化。例如因为您会在分析器中看到它以进行实际测试。

static class HandleCache {
    private final Map<Data, Integer> handles = new HashMap<>();
    private final List<Data> dataByIndex = new ArrayList<>();

    synchronized int getHandle(Data data) {
        Integer id = handles.get(data);
        if (id == null) {
             id = handles.size();
             handles.put(data, id);
             dataByIndex.add(id);
        }
        return id;
    }

    synchronized Data getData(int handle) {
        return dataByIndex.get(handle);
    }
}

关于java - ConcurrentHashMap.computeIfAbsent 中的赋值是线程安全的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49945202/

相关文章:

java - 为什么我的解决方案对于反转整数是错误的?

java - 在包 'layout_width'/新包中找不到属性 'android' 的资源标识符

multithreading - 线程安全内存管理器: Data race in 320 MB buffer?

c++ - 线程安全 : Multiple threads reading from a single const source

ruby-on-rails - Rails 3 ActiveRecord .skip_callback 线程安全

c# - 哪种方式最适合线程同步?

java - 在 android xml 文件的 edittext View 中引用一个整数

java - 使用并发、线程、静态变量实现 GAE/Java 计数器

Java:带小数的 double 格式

c# - 通过多线程提高性能