【发布时间】:2011-02-17 05:40:54
【问题描述】:
假设您有一个具有可变状态的 Runnable 的 Collection(ConcurrentLinkedQueue)。线程 A 遍历 Collection 并将 Runnables 交给 ExecutorService。 run() 方法更改 Runnables 状态。 Runnable 没有内部同步。
以上是重复动作,工作线程需要查看之前迭代所做的更改。所以一个 Runnable 被一个接一个的工作线程处理,但一次永远不会被多个线程访问 -> 串行线程限制的情况(我希望 ;))。
问题:它是否仅适用于 ConcurrentLinkedQueue/ExecutorSerivce 的内部同步?
更准确地说:如果线程 A 将 Runnable R 交给工作线程 B 并且 B 更改了 R 的状态,然后 A 将 R 交给工作线程 C..C 是否看到 B 所做的修改?
编辑: 也因为答案完全不同,这个问题让我很忙……来自 JCIP,16.2.2 安全出版,p。 346:
[...] 如果线程 A 将 X 放在 BlockingQueue 上(并且随后没有线程修改它)并且线程 B 从队列中检索它,则 B 可以保证在 A 离开时看到 X。这是因为 BlockingQueue 实现有足够的内部同步来确保 put 发生在 take 之前。[...]
因此,由于 ExecutorService 的实现方式,唯一的保证是工作线程始终将 Runnables 视为 提交 线程离开它们。
回到我的场景。首先 A 通过 ExecutorService 将 R 交给 B,一切都很好,B 看到了最新的 R(“BlockingQueue 保证”)。现在 B 修改了 R,然后 A 将其交给 C。所以需要的是 B 留下的 R。但是我们得到的是R作为A离开了它。
在 B 中所做的更改不能保证在 A 中可见,即使 B 在 A 将其交给 ExecutorService 之前完成了 R 的执行。 在运行 R 之后,A 和 B 之间没有同步。也许 B 将一个变量加载到某种本地缓存中并在那里更新它。
那么如果A在B执行后看不到R的当前状态,C怎么能看到呢?缺少的是从工作线程返回到 A 的安全发布。
如果我错了,这意味着 B 所做的修改对 A 是可见的,尽管 B 除了拍摄之外不进行同步。这种保证隐藏在哪里?
【问题讨论】:
-
我认为它不能那样工作..但是问题是:除了使 Runnable 线程安全之外,我怎样才能实现我想要的?有没有机制可以让工作线程修改对象后的整个状态可见?
-
你为什么不想让runnable同步?这似乎是您想要的 - 提供序列化执行并使更改对其他线程可见。它还明确了您正在做什么以及您期望的行为,这比依赖某些组件(例如执行程序)的内部或细节更可靠和可维护。
-
我们为什么不让所有东西都同步呢? - 性能问题。
标签: java concurrency synchronization