多线程------------volatile

主要记录学习中的**思路**和**看法**
                               看不懂的话,选中该语句,右键 搜索

线程间通信---------共享主内存(不是缓存)
可见性:

可见性和cpu对主内存的读写优化有关,cpu对主内存读写速度更不上cpu计算速度。
远古时代cpu是直接对内存进行直接读写,演变成, 先对高速缓存读写(提前加载一部分主内存数据----原理:局部性原理(右键),解释了到底加载哪部分内存),
而缓存的数据就会出现与主内存数据不一致的情况,因此这种情况造成多线程下出现了变量不可见的现象。

多线程------------volatile_第1张图片

3种结束线程一的方式

1:使用volatile修饰的变量进行读写
2:使用锁 synchronized (App.class){}
3:禁用JIT 参数(-Djava.compiler=NONE)           

下面这段代码 对方式3解读 对aa的读取每次应该从主内存中读取(个人观点 没有变量副本保存)但是JIT会优化(利用cpu缓存,生成下面代码) 导致一值读的是副本值
方式 1 2 基本相似 使缓存失效,重新从主内存加载数据

while (!aa) {
            }
//            boolean t=aa;
//            while (!t) {
//            }
 public static volatile int i = 0;
 private static boolean aa = false;
 public static void main(String[] args) throws InterruptedException {
//        static boolean aa = false;
 //线程一
 new Thread(() -> {
            System.out.println("thread 1 run.....");
 while (!aa) {
 //                int a=i;
//                synchronized (App.class){}
            }
//            boolean t=aa;
//            while (!t) {
//            }
 System.out.println("thread 1 end.....");
 }).start();
 TimeUnit.SECONDS.sleep(2);
 //线程二
 new Thread(() -> {
            aa = true;
 while (true){}
             }).start();
 }

可见性功能实现
volatile---jvm规范中描述 有volatile 修饰 该变量就不能被缓存
底层实现 就是 读写屏障(cpu提供支持实现)
写内存屏障:能让写入缓存中的最新数据更新写入主内存,让其他线程可见(能读到最新的)
解读:写完volatile变量时,会把他之前普通变量写的一并更新到主内存
对于这种强制写入主内存,cpu就不会因为性能考虑而去对指令重排

读内存屏障:可以让高速缓存中的数据失效,强制重新从主内存加载数据
强制读取主内存内容,让cpu缓存与主内存保持一致,就避免了缓存造成的一致性问题

说了这么多  本质:缓存数据不一致造成 可见性问题   于是让 缓存失效 重新加载   
                性能降低   没有重排序 没有缓存 
可见性:会附带更新其他数据  (缺点 造成 伪共享(右键) 影响性能)
重排序 :只想说 可见性的附赠品 只保证对volatile修饰的变量操作不会被重排序  i++ 别看只有一行 这只是代码层次
下面还有  字节码 ---jvm ----汇编----机器指令--- 层层包装

synchronized

    细节:synchronized 使得多线程 串行执行 保证原子性 
        加锁和释放锁 等同于 读写屏障    保证可见性
        串行就相当于单线程  变相的有序性  (因此有重排可能,不像volatile强制禁止重排) 也就是dcl+volatile 的原因

你可能感兴趣的:(java,volatile,安全)