标签: happens-before

Java内存模型:volatile变量和之前发生的

我想澄清一下,在关系与volatile变量一起工作之前会发生什么.我们有以下变量:

public static int i, iDst, vDst;
public static volatile int v;
Run Code Online (Sandbox Code Playgroud)

和线程A:

i = 1;
v = 2;
Run Code Online (Sandbox Code Playgroud)

和线程B:

vDst = v;
iDst = i;
Run Code Online (Sandbox Code Playgroud)

以下语句是否符合Java内存模型(JMM)?如果没有,那么正确的解释是什么?

  • i = 1总是发生在以前 v = 2
  • v = 2 发生 vDst = v在JMM 之前,只有它实际发生在时间之前
  • i = 1 发生 iDst = i在JMM 之前(并且iDst可以预测分配1)如果v = 2实际发生vDst = v在时间之前
  • 否则,在i = 1和之间的顺序iDst …

java volatile java-memory-model thread-synchronization happens-before

36
推荐指数
3
解决办法
2367
查看次数

内存一致性 - 发生在Java之前的关系之前

在阅读有关内存一致性错误的Java文档时.我找到了与两个创造事件相关的点 - 在关系之前:

  • 当一个语句调用时Thread.start(),与该语句有一个before-before关系的每个语句也与新线程执行的每个语句都有一个before-before关系.新线程可以看到导致创建新线程的代码的影响.

  • 当一个线程终止并导致Thread.join()另一个线程返回时,终止
    线程执行的所有语句
    与成功连接后的所有语句都有一个before-before关系.现在,执行连接的线程可以看到线程中代码的效果.

我无法理解他们的意思.如果有人用一个简单的例子解释它会很棒.

java java.util.concurrent happens-before

33
推荐指数
3
解决办法
1万
查看次数

如果不需要该值,Java 是否允许优化掉易失性读取,同时删除同步之前发生的操作?

以下代码示例显示了一种常见方法,用于演示由于缺少发生之前关系而导致的并发问题。

private static /*volatile*/ boolean running = true;
    
public static void main(String[] args) throws InterruptedException {
    new Thread() {
        @Override
        public void run() {
            while (running) {
                // Do nothing
            }
        }
    }.start();
    Thread.sleep(1000);
    running = false;
}
Run Code Online (Sandbox Code Playgroud)

如果runningvolatile,程序保证在大约一秒后终止。但是,如果running不是volatile,则根本无法保证程序终止(因为在running这种情况下没有发生之前关系或保证变量更改的可见性),而这正是我的测试中发生的情况。

根据JLS 17.4.5,人们还可以通过写入和读取另一个volatile变量来强制执行发生前关系running2,如以下代码示例所示。

private static boolean running = true;
private static volatile boolean running2 = true;
    
public static void main(String[] args) throws InterruptedException {
    new Thread() …
Run Code Online (Sandbox Code Playgroud)

java multithreading volatile java-memory-model happens-before

16
推荐指数
1
解决办法
555
查看次数

发生在直接的ByteBuffer之前

我在一个线程中有一个直接的ByteBuffer(off-heap),并使用JMM给我的一种机制安全地将它发布到另一个线程.之前发生的关系是否扩展到ByteBuffer包装的本机(堆外)内存?如果不是,我怎样才能安全地将直接ByteBuffer的内容从一个线程发布到另一个线程?

编辑

这不是重复的多个线程可以在Java中看到直接映射的ByteBuffer上的写入吗?因为

  • 我不是在谈论一个mmaped()区域,而是一个普遍的堆外区域
  • 我正在安全地发布ByteBuffer
  • 我不是同时修改ByteBuffer的内容,我只是将它从一个线程变为另一个线程

编辑2

这不是使Java的ByteBuffer线程安全选项的重复我不是试图从两个不同的线程同时修改ByteBuffer.我试图从一个线程转到另一个线程并且在由直接ByteBuffer支持的本机内存区域上的语义之前发生.一旦交接,第一个线程将不再修改或读取ByteBuffer.

java multithreading nio happens-before off-heap

11
推荐指数
1
解决办法
268
查看次数

Java发生之前和线程安全

假设我有一个包装HashMap的类,如下所示:

public final class MyClass{

     private final Map<String, String> map;

     //Called by Thread1
     public MyClass( int size ){
         this.map = new HashMap<String, String>( size );
     }

     //Only ever called by Thread2
     public final String put( String key, String val ){
        return map.put( key, value );
     }

     //Only ever called by Thread2
     public final String get( String key ){
        return map.get( key );
     }

     //Only ever called by Thread2
     public final void printMap(  ){
       //Format and print the contents of the …
Run Code Online (Sandbox Code Playgroud)

java concurrency multithreading thread-safety happens-before

10
推荐指数
1
解决办法
357
查看次数

.awaitTermination()是否在执行程序中完成工作之前发生了?

问题我已经多年了:在这个伪代码中,

ExecutorService svc = Executors.newFixedThreadPool(3);
svc.submit(new Runnable() { /* code A */ });
svc.shutdown();
if(svc.awaitTermination(...)) {
    // code B
Run Code Online (Sandbox Code Playgroud)

.awaitTermination()没有记录在代码A和B之间发生的事情. 有没有理由不是

ExecutorService的concurrent包的javadoc定义的之前发生完成的任务和工作之间之前,他们已提交,但不执行的任务和代码之间的成功后.awaitTermination()调用.

注意,我不是要求设计批评如何重构我的代码以利用记录的事先关系.我的问题是,在这种情况下,有没有理由说文档没有提及?

(请注意,尽管标题非常贴切,但这并不是22665198的重复.)

java concurrency executorservice memory-barriers happens-before

10
推荐指数
1
解决办法
271
查看次数

我是否有重新排序问题,是否因为参考逃脱?

我有这个类,我在那里使用它们来缓存实例并克隆它们(数据是可变的).

我想知道我是否可以面对这个重新排序的问题.

我已经看过这个答案和JLS,但我仍然没有信心.

public class DataWrapper {
    private static final ConcurrentMap<String, DataWrapper> map = new ConcurrentHashMap<>();
    private Data data;
    private String name;

    public static DataWrapper getInstance(String name) {
        DataWrapper instance = map.get(name);
        if (instance == null) {
            instance = new DataWrapper(name);
        }
        return instance.cloneInstance();
    }

    private DataWrapper(String name) {
        this.name = name;
        this.data = loadData(name);  // A heavy method
        map.put(name, this);  // I know
    }

    private DataWrapper cloneInstance() {
        return new DataWrapper(this);
    }

    private DataWrapper(DataWrapper that) {
        this.name …
Run Code Online (Sandbox Code Playgroud)

java multithreading java-memory-model happens-before

10
推荐指数
2
解决办法
317
查看次数

不稳定的出版物保证多深?

众所周知,如果我们有一些对象引用并且此引用具有final字段 - 我们将看到来自final字段的所有可到达字段(至少在构造函数完成时)

例1:

class Foo{
    private final Map map;
     Foo(){
         map = new HashMap();
         map.put(1,"object");
     }

     public void bar(){
       System.out.println(map.get(1));
     }
}
Run Code Online (Sandbox Code Playgroud)

正如我在这种情况下所做的那样,我们保证bar()方法总是输出object因为:
1.我列出了完整的类代码,Foo并且map是final;
2.如果某个线程会看到引用Foo和引用!= null,那么我们保证从最终map引用值可以到达的是实际的.

我也是这么认为的

例2:

class Foo {
    private final Map map;
    private Map nonFinalMap;

    Foo() {
        nonFinalMap = new HashMap();
        nonFinalMap.put(2, "ololo");
        map = new HashMap();
        map.put(1, "object");
    }

    public void bar() {
        System.out.println(map.get(1));
    }

    public void bar2() {
        System.out.println(nonFinalMap.get(2));
    }
}
Run Code Online (Sandbox Code Playgroud)

在这里,我们对bar() …

java concurrency visibility volatile happens-before

8
推荐指数
1
解决办法
829
查看次数

“之前发生了什么”是什么意思?

在C ++草案标准中多次使用了“在……之前发生”一词。

例如:终止 [basic.start.term] / 5

如果在调用std?::?atexit之前强烈完成了具有静态存储持续时间的对象的初始化(请参见[support.start.term]),则对该函数的调用将传递给std?::?atexit。在调用对象的析构函数之前进行排序。如果对std?::?atexit的调用很强地发生在具有静态存储持续时间的对象的初始化完成之前,则在传递给std?::?atexit的函数的调用之前对对象的析构函数的调用进行排序。 。如果对std?::?atexit的调用在另一次对std?::?atexit的调用之前强烈发生,则传递给第二个std?::?atexit调用的函数的调用将在传递给函数的函数的调用之前按顺序进行。第一个std?::?atexit调用。

并在 数据竞赛 [intro.races] / 12中定义

评估A发生在评估D之前,如果发生以下情况之一

(12.1)A在D之前排序,或

(12.2)A与D同步,并且A和D都是顺序​​一致的原子操作([atomics.order]),或者

(12.3)对B和C进行求值,使得A在B之前排序,B恰好在C之前发生,而C在D之前排序,或者

(12.4)有一个评估B,使得A强烈发生在B之前,而B强烈发生在D之前。

[注意:非正式地,如果A强烈地发生在B之前,那么在所有情况下A似乎都在B之前被评估。强烈发生在排除消耗操作之前。—尾注]

为什么引入“强烈发生”?直觉上,它与“之前发生的事情”有什么区别和关系?

注释中的“在所有情况下A似乎都在B之前被评估”是什么意思?

(注意:此问题的动机是Peter Cordes在此答案下的评论。)

标准报价附加草案(感谢Peter Cordes)

有序性和一致性[atomics.order] / 4

满足以下约束的所有memory_order?::?seq_cst操作(包括栅栏)上只有一个总顺序S。首先,如果A和B是memory_order?::?seq_cst运算,并且A强烈地发生在B之前,那么A在S中先于B。其次,对于对象M上的每对原子操作A和B,A的相干性在B之前,S必须满足以下四个条件:

(4.1)如果A和B都是memory_order?::?seq_cst操作,则A在S中先于B;和

(4.2)如果A是一个memory_order?::?seq_cst操作,而B发生在memory_order?::?seq_cst栅栏Y之前,则A在S中位于Y之前;和

(4.3)如果memory_order?::?seq_cst栅栏X发生在A之前,而B是memory_order?::?seq_cst操作,则X在S之前位于B之前;和

(4.4)如果memory_order?::?seq_cst防护栏X发生在A之前,而B发生在memory_order?::?seq_cst防护栏Y之前,则X在S中位于Y之前。

c++ multithreading memory-model language-lawyer happens-before

8
推荐指数
1
解决办法
146
查看次数

最终的多线程保证和Java中的内存模型有什么关系?

内存模型在 17.4 中定义。内存模型

17.5 中给出了现场final多线程保证。最终字段语义

我不明白为什么这些是单独的部分。

AFAIKfinal和内存模型都提供了一些保证。
任何真正的程序执行都必须遵守这两个保证。
但现在很清楚这些final保证是否适用于用于验证 17.4.8 中因果关系要求的中间执行。执行和因果关系要求

另一个不清楚的时刻是17.5.1。Final Fields 的语义定义了一个新的“special” ,它与内存模型happens-before中的不同:happens-before

happens-before排序不会与其他happens-before排序传递地关闭。

如果它们相同happens-before,则happens-before不再是偏序(因为它不具有传递性)。
我不明白这怎么不会破坏事情。

如果这些不同happens-before,那么就不清楚 17.5 中的是什么。Final Field Semantics确实如此。17.4中
内存模型用于限制读取可以返回的内容:happens-before

非正式地,如果没有happens-before排序来阻止r读取,则允许读取查看写入的结果。w

但是17.5。最后的字段语义是一个不同的部分。

java final java-memory-model jls happens-before

8
推荐指数
1
解决办法
181
查看次数