并发之一个问题引发的思考

一个问题引发的思考

public class ThreadProblem {
    static boolean stop = false;
​
    public static void main(String[] args) throws InterruptedException {
        Thread thread=new Thread(()->{
            int i=0;
            while(!stop){
                i++;
            }
        });
        thread.start();
        Thread.sleep(1000);
        stop=true;
    }
}
​

预期1s后程序退出,为啥没有呢? stop对线程不可见造成的?

在i++后加入打印语句可以顺利结束?
    jvm server版本hotspot的JIT对指令优化的结果,这里分为两个层面来解答
println底层用到了synchronized这个同步关键字,这个同步会防止循环期间对于stop值的缓存。因为println有加锁的操作,而释放锁的操作,会强制性的把工作内存中涉及到的写操作同步到主
内存,可以通过如下代码去证明。
​
public class ThreadProblem {
    volatile static boolean stop = false;
​
    public static void main(String[] args) throws InterruptedException {
        Thread thread=new Thread(()->{
            int i=0;
            while(!stop){
                i++;
                synchronized (ThreadProblem.class){
​
                }
​
            }
        });
        thread.start();
        Thread.sleep(1000);
        stop=true;
    }
}
​
​
第三个角度,从IO角度来说,print本质上是一个IO的操作,我们知道磁盘IO的效率一定要比CPU的计算效率慢得多,所以IO可以使得CPU有时间去做内存刷新的事情,从而导致这个现象。比如我们可以在里面定义一个new File("xxx.txt")。同样会达到效果.
​

Thread.sleep(0)也可结束程序退出?

这个我认为是和cpu、以及jvm、操作系统等因素 有关系。 官方文档上是说,Thread.sleep没有任何同步语义,编译器不需要在调用Thread.sleep之前把缓存在寄 存器中的写刷新到给共享内存、也不需要在Thread.sleep之后重新加载缓存在寄存器中的值。 编译器可以自由选择读取stop的值一次或者多次,这个是由编译器自己来决定的。 但是Thread.sleep(0)导致线程切换,线程切换会导致缓存失效从而读取到了新的值。

 

对stop变量使用volatile关键字可以解决线程间的可见性问题。

 

总线锁重量级的 先尝试使用缓存锁

 

cpu 内存 io 速度不一致出现了 MESI 协议 --》 store Buffer --》指令重排序-》内存屏障

你可能感兴趣的:(java,多线程,java,多线程)