jAVA 之 volatile 一系列问题

说到valatile,那他是什么?能干什么?怎么用呢?让我们来进一步了解。

Volatile

是jvm多线程轻量级的同步机制

如果不在多线程的条件下使用volatile那么将无任何意义.

Volatile有哪些特性?

 1. 保证可见性(某一个线程修改主内存中的值,那么其他线程就会马上得到同通知)
 2. 不保证原子性(不保证在多个线程同时操作同一个变量的时候,不会出现写覆盖)
 3. 禁止指令重排(防止汇编源码重新排列)

上面说的什么我怎么有点糊涂?

不要急下面我们慢慢来讲解。
说到上面的3个特性,那我们得从JMM说起?

什么是JMM?

Jmm(JAVA 内存模型JAVA Memory Model,简称JMM)本身是一种抽象的概念,并不真实存在,它描述的是一组规则或规范,通过这组规范定义了程序中各个变量(包括实例字段,静态字段,构成数组对象的元素)的访问方式.

JMM有哪些特性?

 1. 可见性(某一个线程修改主内存中的值,那么其他线程就会马上得到同通知)
 2. 原子性
 3. 有序性

JMM关于同步的规定:

  1. 线程解锁前,必须把共享变量的值刷新回内存.
  2. 线程加锁前,必须读取内存的最新值到自己的工作区
  3. 加锁,解锁是同一把锁.

由于JVM运行程序的实体是线程,而每个线程创建时JVM都会为其创建一个工作内存(有些地方称为栈内存空间),工作内存是每一个线程的私有数据区域,而java内存模型中规定所有变量都存储在主内存,主内存是共享变量的区域,所有线程都可以访问,但线程对变量的操作(读取赋值等)必须在内存中进行,首先要将变量从主内存拷贝到自己的内存空间,然后对变量进行操作,操作完之后将变量写回主内存,不能直接操作主内存的变量,各个线程中的工作内存存储着主内存中的变量副本拷贝,因此不同的线程无法访问对方的工作内存,线程间的通讯(传值)必须通过主内存来完成,其简要访问如下图:
jAVA 之 volatile 一系列问题_第1张图片
根据这个图我们在来看看Volatile的可见性:

public class Count_demo {
     
    public static  int count = 0;
    public static void main(String[] args) {
     
        for (int i = 0; i < 20; i++) {
     
            new Thread(new Runnable() {
     
                @Override
                public void run() {
     
                    for (int i1 = 0; i1 < 1000; i1++) {
     
                        count ++ ;
                    }
                }
            },String.valueOf(i)).start();
        }
        System.out.println("count 的和为:"+count);
    }
}

上述代码我们 没有加 Volatile修饰 看看 结果
jAVA 之 volatile 一系列问题_第2张图片
显然 结果 为 0 ,那么 这是 为什么 呢 ,其实 就是 每个内存 都在 操作自己的内存,
并没有把自己内存空间里的值写回主内存…

那么我们将进一步认证:

public class Count_demo {
     
    public static  int count = 0;

    public static void main(String[] args) {
     

        for (int i = 0; i < 20; i++) {
     
            new Thread(new Runnable() {
     
                @Override
                public void run() {
     
                    for (int i1 = 0; i1 < 1000; i1++) {
     
                        count ++ ;

                    }
                    System.out.println(Thread.currentThread().getName()+"值为:" + count);
                }
            },String.valueOf(i)).start();
        }

        System.out.println("count 的和为:"+count);
    }
}

结果 :
jAVA 之 volatile 一系列问题_第3张图片
简单明了 每个 线程都是在 操作属于自己的那块空间,并没有把值写会主内存.
那么现在让我们加volatile:

public class Count_demo {
     
    public static  volatile int count = 0;

    public static void main(String[] args) {
     

        for (int i = 0; i < 20; i++) {
     
            new Thread(new Runnable() {
     
                @Override
                public void run() {
     
                    for (int i1 = 0; i1 < 1000; i1++) {
     
                        count ++ ;

                    }
                    System.out.println(Thread.currentThread().getName()+"值为:" + count);
                }
            },String.valueOf(i)).start();
        }

        System.out.println("count 的和为:"+count);
    }
}

结果:
jAVA 之 volatile 一系列问题_第4张图片
很显然出现了重复写的动作;
那我我们 就来论述一下 这个 重复写的过程:
jAVA 之 volatile 一系列问题_第5张图片打个比方就是在程序语言里java会把.java文件编译成.class文件,再把class文件编译成一种汇编语言,在这个汇编语言中每一行会有自己的标识,及时其他线程抢到cpu,当此线程在执行的时候会在汇编码里找到对应的行继续执行.

你可能感兴趣的:(java)