Java内存模型(JMM)-volatile-JMM笔记01

27 篇文章 0 订阅

Java内存模型(JMM)-volatile

1.引入

线程内存描述
多线程使用的是共享变量的副本,对副本进行更改,并不会影响其他线程。

public class VolatileVisibilityTest {
    private static boolean initFlag = false;
    public static void main(String[] args) throws InterruptedException {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("waitig data....");
                while(!initFlag) {}
                System.out.println("++++++++++++++++");
            }
        }).start();
        Thread.sleep(2000);

        new Thread(new Runnable() {
            @Override
            public void run() {
                prepareData();
            }
        }).start();
    }
    public  static void prepareData() {
        System.out.println("prepareData    beg");
        initFlag = true;
        System.out.println("prepareData end");
    }
}

执行上面代码,发现不同线程间对initFlag的操作互不影响。
如果在变量添加volatile,不同线程之间就会相互感知。
private static volatile boolean initFlag = false;
在这里插入图片描述

2. jmm数据原子操作
  • read(读取):从主内存中读取数据
  • load(载入):将主内存读取到的数据写入工作内存
  • use(使用):从工作内存读取数据来计算
  • assign(赋值):将计算好的值重新赋值到工作内存中
  • store(存储):将工作内存数据写入主内存
  • write(写入):将store过去的变量值赋值给主内存中的变量
  • lock(锁定):将主内存变量加锁,标识为线程独占状态
  • unlock(解锁):将主内存变量解锁,解锁后其他线程可以锁定该变量

在这里插入图片描述
早期加锁:例如线程B读取到initFlag,会给其lock,然后B通过一系列操作后,再通过write写入操作后的initFlag,最后才使用unlock,其他线程才可以访问initFlag

MESi缓存一致性协议
多个cpu从主内存读取同一个数据到各自的高速缓存,当其中某个cpu修改了缓存里的数据,该数据会马上同步回主内存,其它cpu通过总线嗅探机制可以感知到数据的变化从而将自己缓存里的数据失效

如果没有缓存一致性协议,那么一个线程对initFlag修改后,会等到该线程结束,才会将修改store到主内存中。
嗅探机制:其实是一种监听方式

Volatile缓存可见性实现原理
底层实现主要是通过汇编lock前缀指令,它会锁定这块内存区域的缓存(缓存行锁定)并回写到主内存
**1)**会将当前处理器缓存行的数据立即写回到系统内存。
**2)**这个写回内存的操作会引起在其他CPU里缓存了该内存地址的数据无效(MESI协议),然后通过监听获取主内存数据。

volatile也会对共享数据加锁,只是加锁不是在read过程,而是在store时给数据加锁。
思考:这样的好处是什么呢?

加锁的密度减小

·并发编程三大特性:可见性,原子性,有序性
. volatile保证可见性与有序性,但是不保证原子性,保证原子性需要借助
synchronized这样的锁机制

public class VolatileAtomic{
	public static volatile int num = 0;
	public static void increase() {
		num++;
	}
	public static void main(String[]args)throws InterruptedExcepting{
		Thread[] threads = new Thread[10];
		for(int i=0;i<threads.length;i++){
			threads[i] = new Thread(new Runnable(){
				@Override
				public void run() {
					for(int i=0;i<1000;i++){
						increase();
					}
				}
			});
			threads[i].start();
		}
		for(Thread t : threads){
			t.join();
		}
		System.out.println(num);
	}
}

打印结果必定小于等于10000,原因就是volatile不能保证原子性

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值