重要编辑我知道在发生两个赋值的线程中 "发生在之前" 我的问题是,另一个线程是否可能读取"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) 我想澄清一下,在关系与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 = 2v = 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
在阅读了更多的博客/文章等之后,我现在对内存屏障之前/之后的加载/存储行为感到困惑.
以下是Doug Lea在他关于JMM的一篇澄清文章中的两个引用,它们都非常简单:
对我来说,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) Dalvik的内存模型与Java相同吗?我特别感兴趣的是否读取和写入参考和非long/非double原始变量是原子,但我也想知道有没有这两个平台的内存模型之间的差异.
我找不到一个能够以清晰的方式解释这个概念的综合资料来源.我的理解是,在eden中为线程分配了一些新的对象.一个竞争的线程最终会有一些连续的伊甸园.如果第一个线程在其TLAB中用完了空闲区域会发生什么?它会要求新的伊甸园吗?
假设我们有一个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*a的a+a吗?
一方面,易失性读取的目的是它应该始终从内存中消失.
另一方面,两个读取之间没有同步点,所以我看不出a+a原子处理是非法的,在这种情况下我不会看到如何进行优化2*a会破坏规范.
我们将不胜感激参考JLS.
我们volatile在其中一个项目中使用它来维护不同线程访问的变量的相同副本.我的问题是,它是否是正常的使用volatile有static.编译器没有给出任何错误,但我不明白使用两者的原因.
我看了这个问题,如何做双检锁:
// 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
我的问题是对此问题的扩展:易失性保证和无序执行
为了使它更具体,让我们假设我们有一个简单的类,它在初始化后可以处于两种状态:
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,因此它在"屏障"之前引入,确保无法进行重新排序.由于国家唯一字段写入之前 初始化字段写入和只读后的初始化场被读取,我可以去除挥发性从申报关键字状态,仍然不会看到一个陈旧的价值.问题是:
假设,CountDownLatch用作初始化器而不是标志,如下所示:
class A {
private /*volatile?*/ boolean state;
private final CountDownLatch initialized = new CountDownLatch(1);
boolean getState() throws InterruptedException …Run Code Online (Sandbox Code Playgroud)考虑一下volatile int sharedVar.我们知道JLS为我们提供了以下保证:
w其写入值之前i以sharedVar程序顺序happens-before写入动作;i通过w happens-before的成功读取i从sharedVar由读取线程r;i从sharedVar由读线程r happens-before的所有后续行动r的程序顺序.然而,仍有给出没有挂钟时间的保证,当读线程将观察值i.一个完全不会让读取线程看到该值的实现仍然符合此契约.
我已经考虑了一段时间,我看不到任何漏洞,但我认为必须有.请指出我的推理漏洞.