标签: java-memory-model

易失性保证和无序执行

重要编辑我知道在发生两个赋值的线程中 "发生在之前" 我的问题是,另一个线程是否可能读取"b"非空,而"a"仍为空.所以我知道如果你从与之前调用setBothNonNull(...)的线程相同的线程调用doIt(),那么它就不能抛出NullPointerException.但是如果一个人从另一个线程调用doIt()不是调用setBothNonNull(...)的那个呢?

请注意,这个问题仅仅是对volatile关键字和volatile保证:这是不是synchronized关键字(所以请不要回答"您必须使用同步"因为我没有任何问题要解决:我只是想了解volatile担保关于无序执行(或缺乏保证).

假设我们有一个包含两个volatileString引用的对象,它们被构造函数初始化为null,并且我们只有一种方法来修改两个String:通过调用setBoth(...)并且我们之后只能将它们的引用设置为非null引用(只允许构造函数将它们设置为null).

例如(这只是一个例子,毫无疑问):

public class SO {

    private volatile String a;
    private volatile String b;

    public SO() {
        a = null;
        b = null;
    }

    public void setBothNonNull( @NotNull final String one, @NotNull final String two ) {
        a = one;
        b = two;
    }

    public String getA() …
Run Code Online (Sandbox Code Playgroud)

java volatile java-memory-model

41
推荐指数
2
解决办法
9239
查看次数

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中的内存屏障行为

在阅读了更多的博客/文章等之后,我现在对内存屏障之前/之后的加载/存储行为感到困惑.

以下是Doug Lea在他关于JMM的一篇澄清文章中的两个引用,它们都非常简单:

  1. 线程A在写入易失性字段f时可见的任何内容在读取f时都会对线程B可见.
  2. 请注意,两个线程都必须访问相同的volatile变量才能正确设置before-before关系.情况并非如此,线程A在写入易失性字段f时可见的所有内容在读取易失性字段g后变为线程B可见.

但是当我查看另一篇关于内存障碍的博客时,我得到了这些:

  1. 商店屏障,x86上的"sfence"指令强制屏障之前的所有存储指令发生在屏障之前,并将存储缓冲区刷新到缓存以供发布它的CPU.
  2. 负载屏障,在x86"lfence"指令,强制所有加载指令之后的阻隔后发生障碍,然后等待负载缓冲区对于CPU流失.

对我来说,Doug Lea的澄清比另一个更严格:基本上,这意味着如果负载屏障和存储屏障位于不同的监视器上,则无法保证数据的一致性.但后者意味着即使屏障位于不同的监视器上,数据的一致性也会得到保证.我不确定我是否正确理解这两个,而且我不确定它们中的哪一个是正确的.

考虑以下代码:

  public class MemoryBarrier {
    volatile int i = 1, j = 2;
    int x;

    public void write() {
      x = 14; //W01
      i = 3;  //W02
    }

    public void read1() {
      if (i == 3) {  //R11
        if (x == 14) //R12
          System.out.println("Foo");
        else
          System.out.println("Bar");
      }
    }

    public void read2() {
      if (j == 2) {  //R21
        if (x == 14) //R22
          System.out.println("Foo");
        else
          System.out.println("Bar"); …
Run Code Online (Sandbox Code Playgroud)

java multithreading java-memory-model memory-barriers

32
推荐指数
1
解决办法
5868
查看次数

Dalvik的内存模型与Java相同吗?

Dalvik的内存模型与Java相同吗?我特别感兴趣的是否读取和写入参考和非long/非double原始变量是原子,但我也想知道有没有这两个平台的内存模型之间的差异.

java android memory-model dalvik java-memory-model

30
推荐指数
2
解决办法
4740
查看次数

什么是TLAB(线程本地分配缓冲区)?

我找不到一个能够以清晰的方式解释这个概念的综合资料来源.我的理解是,在eden中为线程分配了一些新的对象.一个竞争的线程最终会有一些连续的伊甸园.如果第一个线程在其TLAB中用完了空闲区域会发生什么?它会要求新的伊甸园吗?

java garbage-collection java-memory-model

29
推荐指数
1
解决办法
7325
查看次数

JIT是否可以在某些表达式中将两个易失性读取合并为一个?

假设我们有一个volatile int a.一个线程呢

while (true) {
    a = 1;
    a = 0;
}
Run Code Online (Sandbox Code Playgroud)

而另一个线程呢

while (true) {
    System.out.println(a+a);
}
Run Code Online (Sandbox Code Playgroud)

现在,JIT编译器发出相应的汇编代码是不合法2*aa+a吗?

一方面,易失性读取的目的是它应该始终从内存中消失.

另一方面,两个读取之间没有同步点,所以我看不出a+a原子处理是非法的,在这种情况下我不会看到如何进行优化2*a会破坏规范.

我们将不胜感激参考JLS.

java jit volatile memory-model java-memory-model

28
推荐指数
2
解决办法
560
查看次数

"volatile"在Java中意味着什么?

我们volatile在其中一个项目中使用它来维护不同线程访问的变量的相同副本.我的问题是,它是否是正常的使用volatilestatic.编译器没有给出任何错误,但我不明白使用两者的原因.

java volatile java-memory-model

26
推荐指数
4
解决办法
2万
查看次数

双重检查锁定没有挥发性

我看了这个问题,如何做双检锁:

// Double-check idiom for lazy initialization of instance fields
private volatile FieldType field;
FieldType getField() {
    FieldType result = field;
    if (result == null) { // First check (no locking)
        synchronized(this) {
            result = field;
            if (result == null) // Second check (with locking)
                field = result = computeFieldValue();
        }
    }
    return result;
}
Run Code Online (Sandbox Code Playgroud)

我的目标是在没有volatile属性的情况下延迟加载字段(而不是单例).初始化后,字段对象永远不会更改.

经过一些测试我的最终方法:

    private FieldType field;

    FieldType getField() {
        if (field == null) {
            synchronized(this) {
                if (field == null)
                    field = Publisher.publish(computeFieldValue());
            } …
Run Code Online (Sandbox Code Playgroud)

java multithreading final java-memory-model double-checked-locking

26
推荐指数
2
解决办法
7046
查看次数

Java:易失性隐含订单保证

我的问题是对此问题的扩展:易失性保证和无序执行

为了使它更具体,让我们假设我们有一个简单的类,它在初始化后可以处于两种状态:

class A {
    private /*volatile?*/ boolean state;
    private volatile boolean initialized = false;

    boolean getState(){
        if (!initialized){
            throw new IllegalStateException();
        }
        return state;
    }

    void setState(boolean newState){
        state = newState;
        initialized = true;
    }
}
Run Code Online (Sandbox Code Playgroud)

初始化的字段被声明为volatile,因此它在"屏障"之前引入,确保无法进行重新排序.由于国家唯一字段写入之前 初始化字段写入和只读初始化场被读取,我可以去除挥发性从申报关键字状态,仍然不会看到一个陈旧的价值.问题是:

  1. 这个推理是否正确?
  2. 是否保证写入初始化字段不会被优化掉(因为它只是第一次改变)并且"屏障"不会丢失?
  3. 假设,CountDownLatch用作初始化器而不是标志,如下所示:

    class A {
        private /*volatile?*/ boolean state;
        private final CountDownLatch initialized = new CountDownLatch(1);
    
        boolean getState() throws InterruptedException …
    Run Code Online (Sandbox Code Playgroud)

java concurrency volatile java-memory-model

23
推荐指数
1
解决办法
983
查看次数

关于可见性及时性的易失性的详细语义

考虑一下volatile int sharedVar.我们知道JLS为我们提供了以下保证:

  1. 写入线程的每个动作在w其写入值之前isharedVar程序顺序happens-before写入动作;
  2. 的值写入i通过w happens-before的成功读取isharedVar由读取线程r;
  3. 成功读取isharedVar由读线程r happens-before的所有后续行动r的程序顺序.

然而,仍有给出没有挂钟时间的保证,当读线程将观察值i.一个完全不会让读取线程看到该值的实现仍然符合此契约.

我已经考虑了一段时间,我看不到任何漏洞,但我认为必须有.请指出我的推理漏洞.

java volatile java-memory-model

21
推荐指数
1
解决办法
1086
查看次数