java内存模型java内存模型规定,将所有的变量都放在主内存,当线程使用变量时,会把该变量复制到线程的工作内存,因此线程读写变量操作的是自己工作内存中的变量。下图是一个双核cu的系统架构,每个核都有自己的控制器、运算器、一级缓存,其中控制器包含一组寄存器和操作控制器,运算器负责进行算术逻辑运算。在这个架构中cu还共享一个二级缓存。
其中java内存模型里的线程工作内存对应就是一级缓存、二级缓存、cu寄存器[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DENnjQu-1592028132913)(imagessted-8.ng)]
共享对象可见性例如上图,假设线程A和线程B同时处理一个共享变量,且线程使用不同cu运行,缓存都为空。
线程A首先获取共享变量X的值,由于两级Cache都没有命中,所以加载主内存中X的值,假如为0。然后把X=O的值缓存到两级缓存,线程A修改X的值为1,然后将其写入两级Cache,并且刷新到主内存。线程A操作完毕后,线程A所在的CPU的两级Cache内和主内存里面的X的值都是l。
线程B获取X的值,首先一级缓存没有命中,然后看二级缓存,二级缓存命中了,所以返回X=1;到这里一切都是正常的,因为这时候主内存中也是X=l。然后线程B修改X的值为2,并将其存放到线程2所在的一级Cache和共享二级Cache中,最后更新主内存中X的值为2:到这里一切都是好的。
线程A这次又需要修改X的值,获取时一级缓存命中,并且X=l,到这里问题就出现了,明明线程B已经把X的值修改为了2,为何线程A获取的还是l呢?这就是共享变量的内存不可见问题,也就是线程B写入的值对线程A不可见。(来自于《java并发编程之美》)
使用synchronized和volatile关键字可以解决共享对象的不可见性synchronized关键字synchronized关键字是java提供的一个原子性内置锁(排他锁),同一时间最多只能有一个线程持有相同对象的锁。在线程进入synchronizedd代码块会获得对象锁,其他线程运行到synchronized会被堵塞挂起。
拿到对象锁的线程会在以下情况释放对象锁:
1.正常执行完同步代码块。
2.抛出异常。
3.调用wait等休眠方法synchronized的内存语义进入synchronized代码块会把同步代码块用到的变量从运行线程的工作内存中清除。这样获取变量时就不会从工作内存中获得,而是去主内存中获得。
退出synchronized代码块会把对同步代码块修改的变量刷新到主内存里去。volatile关键字当一个变量被volatile关键字声明时,工作线程获取该变量时会直接从主内存中获得,修改变量值会直接把值刷新到主内存中去。两者对比同:synchronized和volatile都可以实现在多线程中共享对象的可见性。
异:volatile只保证共享对象的可见性,不保证操作的原子性。
synchronized是比较重量级的操作,他会引起线程上下文的切换并带来线程调度开销。
下一篇 类似美团外卖的原生小程序