首页 > 其他 > 详细

Volatile

时间:2021-05-13 00:42:46      阅读:23      评论:0      收藏:0      [点我收藏+]

Volatile

1、保证可见性

package com.chao.cvolatile;
import java.util.concurrent.TimeUnit;
public class JMMDemo {
    //不加 volatile 程序就会死循环!
    //加 volatile 可以保证可见性
    private volatile static int num = 0;
    public static void main(String[] args) { //主线程 main


        new Thread(()->{//线程 1 对主内存的变化不知道的
            while(num==0){

            }
        }).start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        num = 1;
        System.out.println(num);
    }
}

2、不保证原子性

原子性: ACID 不可分割

线程A在执行任务的时候,不能被打扰的,也不能被分割。要么同时成功,要么同时失败。

package com.chao.tvolatile;
// volatile 不保证原子性
public class VDemo02 {
    // volatile 不保证原子性
    private volatile static int num = 0;
    public  static void add(){
        num++;
    }
    public static void main(String[] args) {
        //理论上num结果应该为2万
        for (int i = 1; i <=20; i++) {
            new Thread(()->{
                for (int j = 0; j <1000 ; j++) {
                    add();
                }
            }).start();
        }
        while(Thread.activeCount()>2){ //main gc
            Thread.yield();
        }
        System.out.println(Thread.currentThread().getName() + " " + num);
    }
}

如果不加lock和synchronized,怎么样保证原子性

技术分享图片

使用原子类,解决 原子性问题

技术分享图片

package com.chao.tvolatile;
import java.util.concurrent.atomic.AtomicInteger;
// volatile 不保证原子性
public class VDemo02 {
    // volatile 不保证原子性
    //原子类的 Integer
    private volatile static AtomicInteger num = new AtomicInteger();
    public  static void add(){
        //num++;  //不是一个原子性操作
        num.getAndIncrement(); //AtomicInteger + 1 方法, CAS cpu的并发原语
    }
    public static void main(String[] args) {
        //理论上num结果应该为2万
        for (int i = 1; i <=20; i++) {
            new Thread(()->{
                for (int j = 0; j <1000 ; j++) {
                    add();
                }
            }).start();
        }
        while(Thread.activeCount()>2){ //main gc
            Thread.yield();
        }
        System.out.println(Thread.currentThread().getName() + " " + num);
    }
}

这些类的底层都直接和操作系统挂钩!在内存中修改值!Unsafe类是一个很特殊的存在!

指令重排

什么是 指令重排:你写的程序,计算机并不是按照你写的那样去执行的。

源代码--> 编译器优化的重排-->指令并行也可能会重排-->内存系统也会重排-->执行

处理器在进行指令重排的时候,考虑:数据之间的依赖性问题!

int x = 1; // 1
int y = 2; // 2
x = x + 5; // 3 
y = x * x; // 4
我们所期望的:1234  但是可能执行的时候会变成 2134 1324 
可不可能是   4123!

可能造成影响的结果: a b x y 这四个值默认都是0

线程A 线程B
x=a y=b
b=1 a=2

正常的结果:x = 0; y = 0;但是可能由于指令重排

线程A 线程B
b=1 a=2
x=a y=b

指令重排导致的诡异结果:x=2; y=1;

非计算机专业

volatile可以避免指令重排:

内存屏障,CPU指令。作用:

1、保证特定的操作的执行顺序!

2、可以保证某些变量的内存可见性(利用这些特性volatile实现了可见性)

技术分享图片

Volatile是可以保持 可见性。不能保证原子性,由于内存屏障,可以保证避免指令重排的现象产生!

Volatile

原文:https://www.cnblogs.com/Answer-Chao/p/14761673.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!