java - 实践中的并发设计原则

标签 java concurrency synchronization

我有一个由多个线程同时写入的结果对象。然而,每个线程都有特定的目的并拥有特定的字段,因此实际上没有数据被多个线程修改。在所有写入线程完成写入之前,此数据的消费者不会尝试读取它。因为我知道这是真的,所以数据写入和读取没有同步。

有一个与此 Results 对象关联的 RunningState 对象,用于协调这项工作。它的所有方法都是同步的。当一个线程完成它在这个 Results 对象上的工作时,它会调用 RunningState 对象上的 done() ,它会执行以下操作:递减一个计数器,检查计数器是否已经变为 0(表示所有编写器都已完成),并且如果是,则将此对象放入并发队列。该队列由 ResultsStore 使用,它读取所有字段并将数据存储在数据库中。在读取任何数据之前,ResultsStore 调用 RunningState.finalizeResult(),这是一个空方法,其唯一目的是同步 RunningState 对象,以确保来自所有线程的写入对读取器可见。

这是我的担忧:

1) 我相信这会正常工作,但我觉得我违反了良好的设计原则,不同步对由多个线程共享的对象的数据修改。但是,如果我要添加同步和/或拆分事物以便每个线程只看到它负责的数据,这会使代码复杂化。修改此区域的任何人都应该更好地了解在任何情况下发生了什么,否则他们可能会破坏某些东西,因此从维护的角度来看,我认为带有解释其工作原理的良好注释的更简单的代码是更好的方法。

2) 我需要调用这个什么都不做的方法这一事实似乎表明设计有误。是吗?

意见表示赞赏。

最佳答案

这似乎大部分是正确的,即使有点脆弱(例如,如果您更改一个字段的线程局部性质,您可能会忘记同步它并最终导致难以跟踪的数据竞争)。

主要关注的领域是内存可见性;我不认为你已经建立了它。空的 finalizeResult() 方法可能是同步的,但是如果编写器线程没有同步它同步的任何内容(大概是 this?),那么就没有 happens-before关系。请记住,同步不是绝对的——您相对于也在同一对象上同步的其他线程进行同步。。你的无所事事的方法确实什么都不做,甚至不能确保任何内存屏障。

您需要以某种方式在执行写入操作的每个线程与最终读取的线程之间建立先行发生关系。在没有同步的情况下执行此操作的一种方法是通过 volatile 变量或 AtomicInteger(或其他原子类)。

例如,每个写入线程都可以在对象上调用 counter.incrementAndGet(1),然后读取线程可以检查 counter.get() == THE_CORRECT_VALUE。在写入和读取 volatile/atomic 字段之间存在先行关系,这为您提供了所需的可见性。

关于java - 实践中的并发设计原则,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9610340/

相关文章:

java - 从 XSLT 生成低位不可打印字符

Java plist解析: how to determine if an NSObject is an array or a dictionary

java - 为字符串编写正则表达式

go - 为什么即使有锁,GO 也会出现 'concurrent map writes' panic ?

java - 使用线程执行多项操作,而无需为每项操作使用线程

java - 如何设置SWT按钮前景色?

java - 使用 Future 与 CompletableFuture 的 invokeall()

java - Java中简单多线程程序的奇怪问题

javascript - 与多个页面上的 div 同步内容

session - Tomcat servlet 同步