gpt4 book ai didi

java - 对可变对象的 AtomicReference 和可见性

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:42:16 26 4
gpt4 key购买 nike

假设我有一个 AtomicReference对象列表:

AtomicReference<List<?>> batch = new AtomicReference<List<Object>>(new ArrayList<Object>());

线程 A 将元素添加到此列表:batch.get().add(o);

稍后,线程 B 获取列表,例如,将其存储在数据库中:insertBatch(batch.get());

我是否必须在写入(线程 A)和读取(线程 B)时执行额外的同步以确保线程 B 看到列表的方式与 A 离开它的方式相同,或者这是否由 AtomicReference 处理?

换句话说:如果我有一个指向可变对象的 AtomicReference,并且一个线程更改了该对象,其他线程是否会立即看到此更改?

编辑:

也许一些示例代码是有序的:

public void process(Reader in) throws IOException {
List<Future<AtomicReference<List<Object>>>> tasks = new ArrayList<Future<AtomicReference<List<Object>>>>();
ExecutorService exec = Executors.newFixedThreadPool(4);

for (int i = 0; i < 4; ++i) {
tasks.add(exec.submit(new Callable<AtomicReference<List<Object>>>() {
@Override public AtomicReference<List<Object>> call() throws IOException {

final AtomicReference<List<Object>> batch = new AtomicReference<List<Object>>(new ArrayList<Object>(batchSize));

Processor.this.parser.parse(in, new Parser.Handler() {
@Override public void onNewObject(Object event) {
batch.get().add(event);

if (batch.get().size() >= batchSize) {
dao.insertBatch(batch.getAndSet(new ArrayList<Object>(batchSize)));
}
}
});

return batch;
}
}));
}

List<Object> remainingBatches = new ArrayList<Object>();

for (Future<AtomicReference<List<Object>>> task : tasks) {
try {
AtomicReference<List<Object>> remainingBatch = task.get();
remainingBatches.addAll(remainingBatch.get());
} catch (ExecutionException e) {
Throwable cause = e.getCause();

if (cause instanceof IOException) {
throw (IOException)cause;
}

throw (RuntimeException)cause;
}
}

// these haven't been flushed yet by the worker threads
if (!remainingBatches.isEmpty()) {
dao.insertBatch(remainingBatches);
}
}

这里发生的是我创建了四个工作线程来解析一些文本(这是 Reader in 方法的 process() 参数)。每个 worker 将其已解析的行保存在一个批处理中,并在批处理已满时刷新该批处理(dao.insertBatch(batch.getAndSet(new ArrayList<Object>(batchSize)));)。

由于文本中的行数不是批处理大小的倍数,因此最后的对象最终处于未刷新的批处理中,因为它未满。因此,这些剩余的批处理由主线程插入。

我使用 AtomicReference.getAndSet()用空的替换完整的批处理。这个程序在线程方面是否正确?

最佳答案

嗯……这不是真的。 AtomicReference 保证引用本身在线程中可见,即如果您为它分配一个与原始引用不同的引用,则更新将是可见的。它不保证引用指向的对象的实际内容。

因此,对列表内容的读/写操作需要单独同步。

编辑:因此,从您更新的代码和您发布的评论来看,将本地引用设置为 volatile 足以确保可见性。

关于java - 对可变对象的 AtomicReference 和可见性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9378323/

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