写个可见性的测试代码,发现了一个奇怪的情况
public class VolatileTest2 {
public VolatileTest2(int i) {
i++;
}
static boolean a = false;
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
if (a) {
System.out.println("可见");
break;
}
// 非常的奇怪,new Object和一些自定义类时,没什么问题
// new String和Integer等对象时,竟然打印出来”可见“了,竟然保证的了可见性
// 可见:String、Integer、HashMap、Error、Boolean
// 不可见:自定义类、Object、ArrayList
new Boolean(true);
}
}
}).start();
Thread.sleep(2000);
new Thread(new Runnable() {
@Override
public void run() {
a = true;
}
}).start();
}
为什么在线程的while循环里new一些类的时候就可见了,new另外一些类的时候又不可见了。
该回答引用自ChatGPT
这是因为Java的内存模型规定,当一个线程对一个变量进行修改时,其他线程可能无法立即看到这个变量的最新值,这就是可见性问题。为了保证可见性,需要使用volatile关键字或者synchronized关键字进行同步。
在这个测试代码中,线程1在while循环中尝试读取变量a的值,如果a为true,则输出“可见”并退出循环。而线程2在2秒后将a的值修改为true。由于没有使用同步机制,线程1可能无法立即看到a的最新值。
但是,当线程1在while循环中new String、Integer、HashMap、Error、Boolean等对象时,由于Java中的字符串常量池、整数常量池和一些常用对象可能会被预先加载,所以这些对象的创建可能会触发一些JVM优化,从而使得变量a的最新值能够被线程1立即看到,从而输出“可见”。
而对于自定义类、Object、ArrayList等对象,则没有这些优化,所以线程1无法立即看到变量a的最新值,输出“不可见”。