【问题标题】:Java happend before thread startJava 发生在线程启动之前
【发布时间】:2011-10-04 16:42:02
【问题描述】:

我在某处读到,启动线程对发生前的关系有一些特殊影响。现在我不确定我的代码是否能保证发生之前的关系,所以请赐教。

我有一个 Dispatcher 线程和一个实现 Runnable 接口的 Worker 类。 Dispatcher 线程创建一个新的 Worker 实例,并通过 add 方法用元素填充 Worker 实例中的 LinkedList

然后 Dispatcher 通过 execute 方法将 Worker 实例交给 ExecutorService

然后 Worker 类中的 run 方法开始访问和删除 LinkedList 中的内容。

新启动的 Worker 实例是否看到 LinkedList 的状态与 Dispatcher 留下的相同?或者可能是LinkedList 处于某种不一致的状态?我是否必须以同步方式填写LinkedList

【问题讨论】:

    标签: java concurrency synchronization jvm java-memory-model


    【解决方案1】:

    根据文档:ExecuterService javadocs

    内存一致性效果:线程中的操作在将 Runnable 或 Callable 任务提交到 ExecutorService 之前发生-在该任务采取的任何操作之前,这反过来又发生-在通过 Future.get() 检索结果之前.

    这说明你的概念是正确的。

    【讨论】:

      【解决方案2】:

      Java 语言规范writes

      启动线程的动作同步它启动的线程中的第一个动作。

      如果一个动作x同步一个后续动作y,那么我们也有hb(x, y)

      如果我们有两个动作xy,我们写hb(x, y) 表示x happens-before y

      但是,根据您的描述,不清楚这是否与您的情况相关,因为您谈论的是执行程序,但没有解释该执行程序何时创建或其工作线程启动。

      相关的是Executor's JavaDoc的以下摘录:

      内存一致性效果:线程中的动作之前 将 Runnable 对象提交给 Executor happen-before它的执行开始了,可能在另一个线程中。

      因此您的代码是安全的,只要在提交 Runnable 后调度程序线程不再访问该列表。

      【讨论】:

        【解决方案3】:

        如果使用了锁定或其他同步原语,而您只是使用普通的旧 ArrayList,那么这两个线程可能会看到不同的状态。

        当协调两个独立线程之间的工作时,您必须要么使用线程安全/并发数据结构,要么使用同步代码来保证线程之间一致的“内存快照”。

        这很重要的原因之一是缓存。这两个线程在不同的处理器上同时执行,可能已经将一些对象缓存在不同的本地寄存器中(对于那些处理器来说是本地的)。

        【讨论】:

        • 谢谢,尽管如此。但是调度员永远不会再接触数据。通过构造函数 Worker(LinkedList blahBlah) 传递一个新创建的 LinkedList 是否足够。构造函数在关系之前发生,不是吗?
        • @Franz - 如果调度程序所做的只是构造它们,为什么不让工作线程创建列表?我不完全确定构造函数是否确实建立了发生前的关系。原则上你可能是对的。
        • 该死,我很擅长这些东西,如果不使用,知识会生锈的速度真是令人惊讶。
        猜你喜欢
        • 2015-06-05
        • 2021-03-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-07
        • 1970-01-01
        • 2015-11-21
        相关资源
        最近更新 更多