1)配置热更
第1版:
Map<Integer,ConfLevel> map = xxx;
void init(){
}
这样子的话,等于热更会在另外一个线程执行,会有多线程访问的问题。一个业务线程在遍历,另一个热更线程在修改。
第2版:
Map<Integer,ConfLevel> map;
void init(){
Map<Integer,ConfLevel> temp = xxx; // 配置初始化用临时变量保存
map = localMap;
}
采用局部变量的写法,然后覆盖,局部变量肯定是线程安全的。 但是可见性呢?
第3版:
volatile Map<Integer,ConfLevel> map; // 加上volatile关键字
void init(){
Map<Integer,ConfLevel> temp = xxx;
map = localMap;
}
这样子当map的引用被修改时,是立马知道的。
2)何时死循环
Main3.java
package org.example.test.testVolatile;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
public class Main3 {
public static boolean flag = false;
public static void main(String[] args) {
new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = true;
}).start();
AtomicLong sum = new AtomicLong();
while (!flag) {
// sum.incrementAndGet(); // 这行注释掉就会死循环
}
}
}
查看下字节码
javap -verbose Main3.class
可以看出,会多一条aload_1指令
笔记:要么加volatile,要么就写点有效的代码,光写 init a = 0; 这类无效代码,还是被优化掉。
华珺的话:
我想,因为里面没有操作,虚拟机就不会去 查看flag的值。
你调用一下有代码的方法,依然可以结束。
我一直都知道这里不写东西,就会无限循环(这有个狗头)。
你就算打印一下 sout,都会继续执行下去。 就不会卡在那里无限循环。
只要里面,有 有效代码,就不会无限卡,只会延迟。
我不太在意 编译后到底是什么情况,大概率是因为,不写有效代码,默认编译为了 一个无限执行的命令。如果写了有效代码,每次执行完有效代码,会去查看一下flag,不过都无所谓。知道原因就行了。
什么是有效代码:
无效代码:
int i = 0;
while (!flag) {
// 这个就属于无效代码,加上也照样死循环。
i++;
}
有效代码:
while (!flag) {
// 这个输出属于有效代码,加上就可以避免死循环。
System.out.println("aaa");
}