volatile特性

volatile的特性:

1. 保证可见性
2. 不保证原子性
3. 禁止指令重排

  1. 可见性

可见性:线程变量可以同步主存的共享变量

可见性问题:线程和cpu不是在同一内存中工作,cpu的内存叫做主存,线程的内存叫做工作内存。当线程中某个变量发生了变化,就会同步到主存中,没有变化的就不会同步。可以发现有个缺陷,当线程A和线程B同时调用同一个变量,线程A中没有对这个变量进行操作,而线程B对这个变量进行了操作,并且同步到了主存中。此时会发生一个问题,就是线程A不知道该变量已经被修改。这就产生了可见性问题。

package com.luoKing.Dvolatile;

import java.util.concurrent.TimeUnit;

public class seeyou {

    static int num = 0;

    public static void main(String[] args) throws InterruptedException {

        new Thread(()->{
            while (num==0){

            }
        }).start();

        TimeUnit.SECONDS.sleep(1);

        num++;
        System.out.println(num);
    }

}

我们可以发现程序发生阻塞。
如何解决这个问题呢?

num用volatile修饰,因为volatile可以保证可见性

package com.luoKing.Dvolatile;

import java.util.concurrent.TimeUnit;

public class seeyou {

    static volatile int num = 0;

    public static void main(String[] args) throws InterruptedException {

        new Thread(()->{
            while (num==0){

            }
        }).start();

        TimeUnit.SECONDS.sleep(1);

        num++;
        System.out.println(num);
    }

}

2.不保证原子性

什么是原子性?
原子,组成物质的最小单位,不可再分。原子性操作:不可中断,要么全部执行成功,要么全部执行失败。不能被其他线程干扰。

package com.luoKing.Dvolatile;

public class unatomic {


    private volatile static int num;


    public static int add(){
        return num++;
    }

    public static void main(String[] args) {
        for (int i = 1; i <= 10; i++) {
            new Thread(() -> {
                for (int i1 = 0; i1 < 2000; i1++) {
                    add();
                }
            }).start();
        }
        while (Thread.activeCount()>2){//mian线程和gc线程在有其他线程运行的时候,礼让线程,不执行
            Thread.yield();
        }
        System.out.println("num = " + num);
    }
}

结果

num = 17188

可见volatile并不可以保证原子性

  1. 禁止指令重排

指令重排:我们写的程序,在计算机中执行,并不是按照我们程序的顺序执行,他会重写编排,以达到的最优的性能,但这也会导致运行的结果和我们期望的结果有偏差

加了volatile关键字,在cpu中会产生一个叫做内存屏障的东西,会阻止指令重排
作用:

  1. 保证程序按照特定的顺序操作
  2. 可以保证某些变量的内存可见性
posted @ 2022-05-08 11:38  小罗要有出息  阅读(56)  评论(0编辑  收藏  举报