美文网首页
Java关键字synchronized、volatile的理解

Java关键字synchronized、volatile的理解

作者: PaulLuv | 来源:发表于2018-06-14 23:06 被阅读15次

synchronized -> 同步锁

所有加上synchronized修饰的方法 或 代码块,在同一个时刻,只有一个线程能访问

volatile -> 内存可见性,禁止指令重排序

对于volatile修饰的变量,jvm虚拟机只是保证从主内存加载到线程工作内存的值是最新的.

如同上面所讲的,volatile只是保证从内存加载到线程工作内存的值是最新的,那这里会出现什么问题呢?无法保证操作的原子性

看一下代码:

public class VolatileLearn {
    public static int count = 0;
    public static void add(){
        try {
            Thread.sleep(1000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        count++;
    }

    public static void main(String[] args){
        for (int i=0; i< 1000; i++){
            new Thread(() -> {
                VolatileLearn.add();
            }).start();
        }
        try {
            Thread.sleep(50000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            System.out.println("运行的结果:count =  " + VolatileLearn.count);
        }
    }
}
// 运行的结果:count =  990

上面的例子中,自增操作是不具备原子性的,可分为: 读取变量的原始值、进行加1操作、写入工作内存volatile关键字只保证了读取变量的原始值操作的原子性,并没有保证进行加1操作、写入工作内存的原子性,也就是说会出现两个线程读取到的值(主内存)相同,线程对工作内存操作后的结果一致,最后写入主内存只+1了。

虚拟机在保证执行结果准确性的同时,会对指令进行一定的重排,(来最大性能的发挥CPU?)。
对于new Class来讲,可以分为:
1)创建对象实例
2)执行类的构造函数
3)将实例对象指向分配的内存空间
一般的执行顺序是1-2-3,也可能存在1-3-2这个顺序,如果没有volatile字段修饰,那可能存在某一个线程访问获取这个实例对象,恰好执行到1-3,这时候对象并没有执行完构造函数,是会出问题的。在这个实例对象的变量前添加volatile字段,可以避免指令被重排。

并发编程的三个概念:

相关文章

网友评论

      本文标题:Java关键字synchronized、volatile的理解

      本文链接:https://www.haomeiwen.com/subject/dkyueftx.html