我从Effective Java中读到,在没有同步的情况下,下面的序列A可以被虚拟机转换为序列B并调用它hoisting.我还在某处读到,如果变量未被声明为涉及变量的易失性指令,则可以重新排序.吊装和重新订购同样的东西?
while (!done) sequence A
i++;
if (!done)
while (true) sequence B
i++;
Run Code Online (Sandbox Code Playgroud) 我试着理解为什么这个例子是一个正确同步的程序:
a - volatile
Thread1:
x=a
Thread2:
a=5
Run Code Online (Sandbox Code Playgroud)
因为存在冲突的访问(存在对a的写入和读取)所以在每个顺序一致性执行中必须发生 - 在该访问之间的关系之前.假设一个顺序执行:
1. x=a
2. a=5
Run Code Online (Sandbox Code Playgroud)
1发生在2之前,为什么?
我知道JVM内存模型是针对CPU的最低公分母而设计的,因此它必须假设JVM可以运行的最弱模型(例如ARM).
现在,考虑到x64具有相当强大的内存模型,假设我知道我的程序只能运行在64位x86 CPU上,我可以忽略哪些同步实践?当我的程序通过虚拟化运行时,这也适用吗?
示例:
众所周知,JVM的内存模型需要同步对long和double的读/写访问,但可以假设其他32位原语(如int,float等)的读/写是原子的.
但是,如果我知道,我是一个64位的x86机器上运行,我可以忽略使用上多头锁/双打知道CPU将原子读/写64个值,只是让他们挥发物(像我会整型/花车)?
假设有一个这样的类:
public void MyClass {
private boolean someoneTouchedMeWhenIWasWorking;
public void process() {
someoneTouchedMeWhenIWasWorking = false;
doStuff();
synchronized(this) {
if (someoneTouchedMeWhenIWasWorking) {
System.out.println("Hey!");
}
}
}
synchronized public void touch() {
someoneTouchedMeWhenIWasWorking = true;
}
}
Run Code Online (Sandbox Code Playgroud)
一个线程调用process,另一个调用touch.注意process启动时如何在没有同步的情况下清除标志.
使用Java内存模型,运行的线程是否有可能process看到其本地,非同步写入的效果,即使touch稍后发生?
也就是说,如果线程按此顺序执行:
T1: someoneTouchedMeWhenIWasWorking = false; // Unsynchronized
T2: someoneTouchedMeWhenIWasWorking = true; // Synchronized
T1: if (someoneTouchedMeWhenIWasWorking) // Synchronized
Run Code Online (Sandbox Code Playgroud)
... T1是否有可能从本地缓存中看到值?它可以首先刷新它对内存的所有内容(覆盖T2编写的内容),并从内存中重新加载该值吗?
是否有必要同步第一次写入或使变量变为volatile?
如果答案得到文档或一些可敬的消息来源的支持,我将非常感激.
我正在尝试解决一个简单的问题,并陷入Java内存模型兔子洞.
什么是最简单和/或最有效(判断调用此处),但无竞争(根据JMM精确定义)编写包含非最终引用字段的Java类的方法,该字段初始化为非空值构造函数,后来从未改变过,这样任何其他线程的后续访问都不能看到非空值?
破碎的起始示例:
public class Holder {
private Object value;
public Holder(Object value) {
if (value == null)
throw NullPointerException();
this.value = value;
}
public Object getValue() { // this could return null!
return this.value;
}
}
Run Code Online (Sandbox Code Playgroud)
而根据这篇文章,标记该领域volatile甚至不起作用!
public class Holder {
private volatile Object value;
public Holder(Object value) {
if (value == null)
throw NullPointerException();
this.value = value;
}
public Object getValue() { // this STILL could return null!!
return this.value;
}
} …Run Code Online (Sandbox Code Playgroud) 我想确保根据Java内存模型正确理解'有效不可变对象'的行为.
假设我们有一个可变类,我们希望将其发布为有效的不可变类:
class Outworld {
// This MAY be accessed by multiple threads
public static volatile MutableLong published;
}
// This class is mutable
class MutableLong {
private long value;
public MutableLong(long value) {
this.value = value;
}
public void increment() {
value++;
}
public long get() {
return value;
}
}
Run Code Online (Sandbox Code Playgroud)
我们执行以下操作:
// Create a mutable object and modify it
MutableLong val = new MutableLong(1);
val.increment();
val.increment();
// No more modifications
// UPDATED: Let's say for this example we …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
想象一下,我们在内存中分散了1000个相同类型的对象(它们是在不同时间创建的,其他对象是在其间创建的).
我们有一个数组,它包含对1000个对象中每个对象的引用.
如果我们按顺序遍历数组,那么将预取到CPU的高速缓存中的是什么?只有数组所包含的引用或这些引用才会被解引用,并且对象也会被加载到缓存中?
Java(JVM)是否实现了某种软件预取?如果没有,是否有提供软件预取的库?
我有一些关于程序顺序以及它如何影响JMM中的重新排序.
在Java内存模型中,程序顺序(po)被定义为程序中每个线程中的操作的总顺序.根据JLS,这会导致发生前(hb)边缘:
如果
x并且y是同一个线程的动作并且在程序顺序x之前y,那么hb(x,y)(即x发生在之前y).
所以对于一个简单的程序P:
initially, x = y = 0
T1 | T2
-----------|-----------
1. r1 = x | 3. r2 = y
2. y = 1 | 4. x = r2
Run Code Online (Sandbox Code Playgroud)
我认为po(1,2)和po(3,4).因此,hb(1,2)和hb(3,4).
现在假设我想重新排序其中一些语句,给我P':
initially, x = y = 0
T1 | T2
-----------|-----------
2. y = 1 | 3. r2 = …Run Code Online (Sandbox Code Playgroud) 我有这个类,我在那里使用它们来缓存实例并克隆它们(数据是可变的).
我想知道我是否可以面对这个重新排序的问题.
我已经看过这个答案和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)