根据Java Memory Model,只要执行结构良好,指令就可以重新排序.
所以我想知道,以下代码是否可能产生以下输出?
[代码] [在同一个主题中]
long a = System.currentTimeMillis();
long b = System.currentTimeMillis();
long c = System.currentTimeMillis();
Run Code Online (Sandbox Code Playgroud)
[输出]
a == 10, b == 20, c == 15
Run Code Online (Sandbox Code Playgroud)
如果不可能,那么JVM /实现会做些什么来防止这种情况发生?
在JLS的第17章中,它引入了一个概念:发生在一致之前.
如果对于A中的所有读取r,其中W(r)是r看到的写入动作,那么一组动作A发生 - 在一致之前,不是hb(r,W(r))或那里的情况在A中存在写w,使得wv = rv和hb(W(r),w)和hb(w,r)"
在我的理解中,它等于以下几个词:...,既不是......也不是......
所以我的前两个问题是:
它还给出了一个例子:17.4.5-1
Thread 1 Thread 2
B = 1; A = 2;
r2 = A; r1 = B;
Run Code Online (Sandbox Code Playgroud)
在第一个执行顺序中:
1: B = 1;
3: A = 2;
2: r2 = A; // sees initial write of 0
4: r1 = B; // sees initial write of 0
Run Code Online (Sandbox Code Playgroud)
订单本身已经告诉我们两个线程交替执行,所以我的第三个问题是:左数是什么意思?
在我的理解中,r2和r1的原因可以看出0的初始写入是A和B都不是volatile字段.所以我的第四个问题是:我的理解是否正确?
在第二个执行顺序中:
1: r2 = A; // sees write of A = 2
3: r1 = B; // sees …Run Code Online (Sandbox Code Playgroud) HashMap我的程序中有一个由多个线程访问,偶尔由一个线程设置.
例如:
Map<String, String> myMap = new HashMap<String, String>();
Run Code Online (Sandbox Code Playgroud)
这可以通过多个线程访问.每小时一次,一个线程调用:
myMap = myRefreshedVersionOfTheMap;
Run Code Online (Sandbox Code Playgroud)
所以我的问题是这是否是线程安全的.如果两个映射始终都有密钥"importantKey",那么读取线程是否可以在"importantKey"不存在时访问映射?
编辑:
感谢答案,我意识到这个问题实际上是独立的HashMap.这是一个关于对象引用分配的问题.
java multithreading reference thread-safety java-memory-model
我有这个类,我在那里使用它们来缓存实例并克隆它们(数据是可变的).
我想知道我是否可以面对这个重新排序的问题.
我已经看过这个答案和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并发实践》,在“16.1.3 500字以内的Java内存模型”中,它说:
\n\n\n\n\nJava 内存模型是根据操作来指定的,包括对变量的读取和写入、监视器的锁定和解锁以及线程的启动和加入。JMM为程序中的所有操作定义了一个名为“happens-before”的部分排序。为了保证执行动作B的线程可以看到动作A的结果(无论A和B是否发生在不同的线程中),A和B之间必须存在happens-before关系。在没有happens-before排序的情况下在两个操作之间,JVM 可以随意对它们重新排序。
\n\n尽管动作只是部分有序的,但同步动作\xe2\x80\x94锁的获取和释放以及易失性变量\xe2\x80\x94的读写都是完全有序的。这使得根据 \xe2\x80\x9csubsequent\xe2\x80\x9d 锁定获取和易失性变量的读取来描述发生之前是有意义的。
\n
关于“部分排序”,我找到了这个和这个,但我不太明白“即使动作只是部分排序,同步动作\xe2\x80\x94锁获取和释放,以及易失性变量的读写\ xe2\x80\x94 是完全有序的。” 。“同步操作完全有序”是什么意思?
\n考虑以下代码。
public class Test {
private boolean running = false;
public void run() {
running = true;
}
public void test() {
boolean running1 = running;
boolean running2 = running;
System.out.println("running1: " + running1);
System.out.println("running2: " + running2);
}
}
Run Code Online (Sandbox Code Playgroud)
线程 A 调用run(),然后另一个线程 B 调用test()并且不应该有任何发生之前的关系。我知道不能保证线程 B 看到线程 A 所做的更改。但是这个程序的输出有没有可能是:
running1: true
running2: false
Run Code Online (Sandbox Code Playgroud) java concurrency multithreading thread-safety happens-before