Volatile 轻量级的同步机制的知识点回顾

Volatile 轻量级的同步机制:(三特点)
1.保证可见性
2.不保证原子性
3.禁止指令重排

回顾可见性
JVM 的运行实体是线程,1.每个线程的创建时都是jvm都会为其创建一个工作内存(有些地方称为栈空间)工作内存是每个线程的私有数据区域,而java内存模型中规定所有的变量都存储在主内存主内存是内存共享区域,所有线程都可以访问,但是线程对变量的操作必须是在工作内存中进行的,2.首先要将变量从主内存中拷贝到自己的工作内存空间,然后对变量进行操作,操作完成后再将变量写会主内存中,不能直接操作主内存中的变量,各线程中的工作内存存储着主内存中变量副本拷贝,因此不同的线程间是无法访问对方的工作内存的,3.线程间的通信必须痛过主内存来完成的,其简要访问过程如下图:
在这里插入图片描述
3的过程就是可见性过程:

volatile 的可见性具体代码

package com.ryx;

import java.util.concurrent.TimeUnit;

class MyData{
	// 不加Volatile关键字的情况是 一 结果
	// num变量之前根本没有添加volatile关键字修饰,没有可见性
    // int num=0;
    // 加Volatile关键字的情况是 二 结果
    volatile int num=0;
    public void addData(){
        this.num=60;
    }
}

public class VolatileDemos {
    public static void main(String[] args) {
        seeOkByVolatile();
    }
    // volatile 可以保证可见性,以及及时通知其他线程,主物理内存的值已经被修改过
    private static void seeOkByVolatile() {
        //操作资源类
        MyData myData=new MyData();
        new Thread(()->{
           System.out.println(Thread.currentThread().getName()+"\t come in ");
            try{
                TimeUnit.SECONDS.sleep(3);
            }catch (Exception e){
                e.printStackTrace();
            }
            myData.addData();
            System.out.println(Thread.currentThread().getName()+" \t updated number value: "+myData.num);
        },"AAA").start();

        // 第二个就是我们的main线程了
        while(myData.num == 0){
            // main 函数一直在这里这里等待循环直到num值不在等于零
        }

        System.out.println(Thread.currentThread().getName()+" \t mission is over ,mian get number value: "+myData.num);
    }
}

结果一:

AAA	 come in 
AAA 	 updated number value: 60
// main 就是打不出来,因为主内存的变量并没有被修改,不可见!

结果二:

AAA	 come in 
AAA 	 updated number value: 60
main 	 mission is over ,mian get number value: 60

不保证原子性


具体代码:

package com.ryx;

import java.util.concurrent.TimeUnit;

class MyData{
    //int num=0;
    volatile int num=0;
    public void addPlus(){
        num++;
    }
}

/**
 *
 * 验证volatile不保证原子性
 *  原子性指的什么意思?
 *      不可分割,完整性,也即某个线程整在做某个具体业务时,中间不被加塞,
 *      或者被分割整体完整 要么同时成功,要么同时失败。
 * 
 * 为什么不保证
 *  原因是假如 num的值为0 有三个线程同时来进行数据资源的操作,把num=0 
 * 从主内存写会到线程自己的工作内存,开始进行在自己的工作内存中修改变量,
 * 执行num++操作,将自己的num修改为1,接下来,都开始往主内存中写操作,线程一,二,三都同时写入,
 * 线程一比较强势先修变量改为一,这时线程二,三被挂起了,当线程一还没有进行全部通知
 * 其他线程的时候,线程二,三被又唤醒了,也对原num=1,进行原值覆盖,
 * 这样线程二,三就被漏掉了!本来数值应该为3,但是这样的操作,导致数据为1!
 *
 */
public class VolatileDemos {
    public static void main(String[] args) {
        MyData myData=new MyData();

        for(int i=1;i<=20;i++){
            new Thread(()->{
                for (int j = 0; j <=1000; j++) {
                    myData.addPlus();
                }
            },String.valueOf(i)).start();
        }

        //需要等待上面的20个线程都全部完成,再用main线程去得最终的结果是多少。
        while (Thread.activeCount() >2){
            // 礼让线程
            Thread.yield();
        }
        // 若是volatile能保证原子性,则myData.num打印出来的是2w。
        System.out.println(Thread.currentThread().getName()+"\t final num value: "+myData.num);
    }
}

结果是:

main	 final num value: 19987

Process finished with exit code 0
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值