Volatile

Volatile(关键字)

是一个轻量级的同步机制,一个比较low的Synchronized
保证了可见性,不保证原子性,禁止指令重排(保证有序性);
指令重排: 在数据依赖的情况下,源码的顺序和编译的顺序不一致;所以多个线程中使用的变量能否保证一致性是无法确定的。
所以需要使用关键字Volatile禁止指令重排,从而避免了多线程情况下程序出现乱序执行的现象,也就是避免出现无序性;

public class a{
    int a =11;  //1
    int b =12;  //2
    a=a+5;      //3
    b=a*a;      //4
    //这里可以进行1324等排序; 但是4不能作为开始的数据; 因为没a的数据值的依赖;
}

Volatile 禁止指令重排:

执行写操作的时候,会发出一条store屏障指令;保证被Volatile修饰的变量不会被其他变量进行排序;

执行读操作的时候,会发出一条load屏障指令;禁止其他没有被修饰的读操作和Volatile修饰的变量进行排序;

如果让volatile保证原子性
  1. Synchronized 保证原子性; 2 . 通过使用JUC下面的 AtomicInteger 保证了原子性 底层CAS原理;
JVM运行的实体是线程,而每个线程创建时,JVM都会为其创建一个工作内存;
JMM内存模型就规定.所有的变量都要存储到主内存中去;

在代码验证前要先粗略的讲解JMM内存模型;

JMM本身是一种抽象的概念, 并不是真实存在; 是一种规范. 规定了程序中各个变量的访问方式; (包括实例字段, 静态字段. 和构成数对象的元素), 需要保证 原子性、可见性和有序性;

JMM的同步规定:
1.线程解锁前: 必须把共享变量的值刷新回主内存;(共享内存区域; 存储着所有的变量,所有的线程都可以访问)
2.线程加锁前; ; 必须读取主内存的最新值到自己的工作内存(每个线程私有的数据区域);

可见性

每个线程对数据的**读,写.,赋值,**都需要将变量 拷贝到自己的工作内存中去;然后进行修改操作;并将修改操作的值,写回到主内存中去; 但同时别的线程不知道改了, 所以要通知其他线程,已经有线程对主内存数据进行了修改操作,主内存的数据值,已经不是最新值; 这个就是JMM内存模型中的第一个特性可见性;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

class A {
    //修饰加volatile,让AAA线程修改值,同步可见到其他线程,使本来main线程中while循环判断条件number==0为true的判断变成false;
    //不加的话,main 和 AAA线程之间互相不可见, main线程会一直处于运行状态;
    volatile int number = 0;

    public void add01() {
        this.number = 30;
    }

    public void yuanzixing01() {
        //这个number实现了Volatile;
        this.number++;
    }

    AtomicInteger atomicInteger = new AtomicInteger();

    public void yuanzixing02() {
        //这个number实现了Volatile;
        atomicInteger.getAndIncrement();
    }

}

/**
 * 1. 验证volatile的可见性;
 * 1.1 如果int number =0;  number 的变量前根本没有添加valotile关键字进行修饰. 所以不可见;
 * <p>
 * 2.  保证Volatile 不保证原性;
 * 2.1 不可分割.原子性
 */
public class VolatileDemo01 {
    public static void main(String[] args) {
        //Volatile 可见性的操作;
        //SeeOkByVolatile();
        //验证不保证原子性的方法;
        SeeByyuanzixing();
    }

    //验证不保证原子性的方法; 每次的值都不等于20000 因为线程之间的值都进行了覆盖;
    private static void SeeByyuanzixing() {
        A a = new A();
        for (int i = 1; i <= 10; i++) {
            new Thread(() -> {
                for (int i1 = 1; i1 <= 2000; i1++) {
                    a.yuanzixing01();
                    a.yuanzixing02();  //保证原子性;
                }
            }, "BBB").start();
        }
        while (Thread.activeCount() > 2) {
            Thread.yield();
        }
        System.out.println(Thread.currentThread().getName() + ": finally number value " + a.number);
        System.out.println(Thread.currentThread().getName() + ": finally AtomicInteger number value " + a.atomicInteger);
    }


    //Volatile 可以保证可见性,及时通知其他线程;
    private static void SeeOkByVolatile() {
        A a = new A();   //创建的资源类;
        //实现多线程的方法; 创建线程一: AAA
        new Thread(() -> {
            System.out.println("AAA线程未修改" + Thread.currentThread().getName() + ":   " + a.number);//获取线程的名字;
            try {
                //暂停一会线程;
                TimeUnit.SECONDS.sleep(3);
                //修改值;调用之间定义的方法;  将number的值修改为30;
                a.add01();
                System.out.println("AAA线程修改后获取" + Thread.currentThread().getName() + ":  " + a.number);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "AAA").start();

        //main线程处于循环状态; 直接到number不再等于零;
        while (a.number == 0) {
        }
        System.out.println("运行完毕;");
    }
}

看视频后自行理解,不足点有, 欢迎建议, 必定整改. 不喜勿喷~~

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值