可见性问题
线程2会结束运行吗?
package com.qf;import java.util.concurrent.TimeUnit;public class VolatieDemo {private boolean flag = false;public void setFlag(boolean flag) {this.flag = flag;}public boolean getFlag() {return flag;}public static void main(String[] args) throws InterruptedException {final VolatieDemo demo = new VolatieDemo();final Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {demo.setFlag(true);System.out.println(demo.getFlag());}});final Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {while (!demo.flag){}System.out.println("t2 is done");}});t2.start();TimeUnit.SECONDS.sleep(1);t1.start();}}
JMM (Java Memory Model)
问题起源:CPU和缓存一致性
动态演示缓存一致性协议 MESI
https://www.scss.tcd.ie/Jeremy.Jones/VivioJS/caches/MESIHelp.htm
什么是内存模型
什么是Java内存模型
- Java内存模型将内存划分为主内存和工作内存。
- 所有的变量都存储在主内存中,每个线程有自己的工作内存。
- 线程的工作内存中保存了该线程中是用到的变量的主内存副本拷贝。
- 线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存。
- 不同的线程之间也无法直接访问对方工作内存中的变量。
- 线程间变量的传递均需要自己的工作内存和主存之间进行数据同步进行。
JMM八种原子操作
- lock 锁定 : 把主内存中的一个变量标志为一个线程独享的状态
- unlock 解锁 : 把主内存中的一个变量释放出来
- read 读:将主内存中的变量读到工作内存中
- load 加载:将工作内存中的变量加载到副本中
- use 使用:当执行引擎需要使用到一个变量时,将工作内存中的变量的值传递给执行引擎
- assign 赋值:将执行引擎收的的值赋值给工作内存中的变量
- store 存储:将工作内存中的变量的值传到主内存中
- write 写入:将store得到值放到主内存的变量中
Java内存模型原语
Java内存模型,除了定义了一套规范,还提供了一系列原语,封装了底层实现后,供开发者直接使用。例如,volatile和synchronize关键字。Volatile工作原理分析
volatile如何解决内存可见性的?
Volatile无法解决原子性问题
案例
package com.qf;import java.util.ArrayList;import java.util.List;public class VolatileAtomicDemo {public volatile static int count = 0;public static void main(String [] args) throws InterruptedException {List<Thread> list = new ArrayList<>();//开启10个线程for(int i = 0;i < 10; i++){list.add( new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}//每个线程中让count的值自增100次for(int j = 0;j < 1000;j++){count++;}}}));}for (Thread thread : list) {thread.start();}for (Thread thread : list) {thread.join();}System.out.println("count= " + count);}}
思考:问题出在哪里?
