pr0*_*gma 10 java concurrency multithreading consistency
好吧,我知道这听起来很愚蠢(而且我很害怕),但我对自己给出的答案并不完全满意,所以我认为值得在这里问一下.我正在处理关于并发的练习(在Java中),就像这样
给定已解决的数独图表,使用同时运行的固定数量的线程确定图表是否已正确解决,即不会违反规范规则(数字必须出现在其行,列和其中只阻止一次).
现在我的问题是:由于线程只需执行"读取",从图表中收集信息并在其他地方详细说明,它们不能在不担心并发的情况下工作吗?图表的状态总是一致的,因为没有执行"写入",因此它永远不会改变.
当且仅当存在资源一致性丢失的风险时,是否需要锁/同步块/同步方法?换句话说,我是否以正确的方式理解并发?
这是一个相当微妙的问题,根本不是愚蠢的.
只有在数据结构安全发布的情况下,同时读取数据结构的多个线程才可以在没有同步的情况下这样做.这是内存可见性问题,而不是计时问题或竞争条件.
参见Goetz等的第3.5节.例如,Java Concurrency In Practice,用于进一步讨论安全发布的概念.关于"有效不可变对象"的第3.5.4节似乎适用于此,因为董事会在某一点变得有效不可变,因为它在达到解决状态后永远不会被写入.
简而言之,编写器线程和读取器线程必须执行一些内存协调活动,以确保读取器线程具有对已写入内容的一致视图.例如,编写器线程可以编写数独板,然后在持有锁时,在静态字段中存储对板的引用.然后读取线程可以加载该引用,同时保持锁定.一旦他们完成了这项工作,他们就可以确保所有以前对电路板的写入都是可见且一致的.之后,读取器线程可以自由地访问板结构,而无需进一步同步.
还有其他方法可以协调内存可见性,例如对volatile变量的写入/读取AtomicReference.使用更高级别的并发构造(如锁存器或障碍)或向其提交任务ExecutorService也将提供内存可见性保证.
UPDATE
根据与Donal Fellows的评论中的交换,我还应该指出安全发布要求也适用于从读者线程中获得结果.也就是说,一旦读取器线程中的一个具有来自其计算部分的结果,它就需要在某处发布该结果,以便它可以与其他读取器线程的结果组合.可以像以前一样使用相同的技术,例如在共享数据结构上锁定/同步,挥发性等.但是,这通常是不必要的,因为结果可以从或通过Future返回获得.这些构造自动处理安全发布要求,因此应用程序不必处理同步.ExecutorService.submitinvoke