Java内存模型文档
https://download.oracle.com/otndocs/jcp/memory_model-1.0-pfd-spec-oth-JSpec/
中文版:
http://ifeve.com/jsr133-cn/
由于目前多核CPU与自己的高速缓存交换速度要远远快于和主内存交换,因此如果每个线程都有一个私有副本(工作内存),JVM可以大大提高效率;但带来的后果就是,私有副本要定期和主内存同步,而看上去两个线程在修改同样的一个变量,但实际上由于工作内存的存在,他们其实都在修改自己的私有副本;
public class VolatileTest {
private static boolean cancelled = false;
//有可能存在两个线程共同读写一个副本,导致主线程中cancelled被修改为true时,另一个线程看不到,cancelled 依旧为false
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
while (true) {
if (cancelled) {
//取消自己做的事
break;
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
//做一些定时器相关的工作
}
}
).start();
Thread.sleep(100000);
cancelled = true;
}
}
规避该问题:
volatile的保证
- 可见性,非原子性
- 写入volatile变量会直接写入主内存
- 从volatile变量读取会直接读取主内存
public class VolatileTest {
private static volatile boolean cancelled = false; //这里加volatile 最合适
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
while (true) {
if (cancelled) {
//取消自己做的事
break;
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
//做一些定时器相关的工作
}
}
).start();
Thread.sleep(100000);
cancelled = true;
}
}
- 禁止指令重排
- 编译器和处理器都可能对指令进行重排,导致问题
private static boolean initializationFinished = false;
public static void main(String[] args) throws InterruptedException {
init();
initializationFinished = true;
// 这两个指令没有必要的联系,所以在JIT编译/cpu流水线执行过程中,可能真正执行的顺序与代码顺序相反;
}
private static void init(){
//假装自己在初始化工作
}
private static boolean initializationFinished = false;
// 对于两个线程来说,由于指令重排存在,使得两个线程可能存在先修改initializationFinished = true;而并没有init()的情况;
// 结果导致未初始化就进行后续操作;
public static void main(String[] args) {
init();
initializationFinished = true;
new Thread(() -> {
while (true) {
if (initializationFinished) {
doSomething();
break;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
private static void doSomething() {
//假装自己在初始化结束后,执行一些有意义的工作
}
private static void init() {
//假装自己在初始化工作
}
private static volatile boolean initializationFinished = false;
public static void main(String[] args) {
init();
// 在读之前产生内存屏障
initializationFinished = true;
// 在写之后产生内存屏障
// 阻止指令重排
new Thread(() -> {
while (true) {
if (initializationFinished) {
doSomething();
break;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
private static void doSomething() {
//假装自己在初始化结束后,执行一些有意义的工作
}
private static void init() {
//假装自己在初始化工作
}
- 有同步的时候无需volatile
- synchronized/Lock/AtomicInteger
方法一
public class VolatileTest {
private static boolean initializationFinished = false;
public static void main(String[] args) {
init();
//此时不再需要volatile声明变量
synchronized (VolatileTest.class){
initializationFinished = true;
}
new Thread(() -> {
while (true) {
if (initializationFinished) {
doSomething();
break;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
private static void doSomething() {
//假装自己在初始化结束后,执行一些有意义的工作
}
private static void init() {
//假装自己在初始化工作
}
}
方法二
public class VolatileTest {
private static boolean initializationFinished = false;
static Lock lock = new ReentrantLock();
public static void main(String[] args) {
init();
lock.lock();
initializationFinished = true;
lock.unlock();
new Thread(() -> {
while (true) {
if (initializationFinished) {
doSomething();
break;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
private static void doSomething() {
//假装自己在初始化结束后,执行一些有意义的工作
}
private static void init() {
//假装自己在初始化工作
}
}
方法三
public class VolatileTest {
private static AtomicBoolean initializationFinished = new AtomicBoolean(false);
public static void main(String[] args) {
init();
initializationFinished.set(true);
new Thread(() -> {
while (true) {
if (initializationFinished.get()) {
doSomething();
break;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
private static void doSomething() {
//假装自己在初始化结束后,执行一些有意义的工作
}
private static void init() {
//假装自己在初始化工作
}
}
附:面试-并发容器之ConcurrentHashMap
https://blog.csdn.net/a979331856/article/details/105922069
网友评论