volatile的可见性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| public class VolatileDemo {
public static void main(String[] args) { MyData myData=new MyData();
new Thread(()->{ System.out.println(Thread.currentThread().getName()+"come in"); try{ TimeUnit.SECONDS.sleep(3); }catch (Exception e){
}
myData.addTo60(); System.out.println(Thread.currentThread().getName()+":"+myData.number); },"AAA").start(); while (myData.number==0){
} System.out.println(Thread.currentThread().getName()+"\t"+"mission is over main thread number="+myData.number); } }
class MyData{ int number=0;
public void addTo60(){ this.number=60; } }
|
可见性
由于JVM运行程序的实体是线程,每个线程创建时JVM会为其创建一个工作内存,工作内存是每个线程的私有数据区域,而Java内存模型中规定所有的变量都存储在主内存中,主内存是共享内存区域,所有的线程都可以访问,但线程对变量的操作必须在工作内存中进行,首先要把变量从主内存中拷贝一份到工作内存,在工作内存操作完之后再写回主内存,但是不同线程之间工作内存是不能相互访问的,写回主内存之后要保证其他线程能够及时知道主内存中的变量值变了。这就是可见性。
JMM规范(Java Memory Model)
1.是一个抽象概念,描述一组规则或规范
JMM关于同步的规定
1.线程解锁前,必须把共享变量的值刷新回主内存
2.线程加锁前,必须读取主内存的最新值到自己的工作空间
3.加锁解锁是同一把锁
volatile不保证原子性
javap -c在IDEA 2019.2的配置
-c $FileDir$$FileNameWithoutAllExtensions$.class
$FileDir$
-v -c -s -l -p $OutputPath$$FileDirRelativeToSourcepath$$FileNameWithoutExtension$.class
禁止指令重排
案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
| import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger;
public class VolatileDemo {
public static void main(String[] args) {
MyData myData = new MyData(); for (int i = 0; i < 20; i++) { new Thread(() -> { for (int j = 0; j < 1000; j++) { myData.addPlusPlus(); myData.addAtomic(); }
}, String.valueOf(i)).start(); }
while (Thread.activeCount() > 2) { Thread.yield(); } System.out.println(Thread.currentThread().getName() + "\t" + "finally number is " + myData.number); System.out.println(Thread.currentThread().getName() + "\t" + "finally atomicInteger is " + myData.atomicInteger.get());
}
public void seeOkByVolatile() { MyData myData = new MyData();
new Thread(() -> { System.out.println(Thread.currentThread().getName() + "come in"); try { TimeUnit.SECONDS.sleep(3); } catch (Exception e) {
}
myData.addTo60(); System.out.println(Thread.currentThread().getName() + ":" + myData.number); }, "AAA").start(); while (myData.number == 0) {
} System.out.println(Thread.currentThread().getName() + "\t" + "mission is over main thread number=" + myData.number);
} }
class MyData { volatile int number = 0;
AtomicInteger atomicInteger=new AtomicInteger(); public void addAtomic(){ atomicInteger.getAndIncrement(); }
public void addTo60() { this.number = 60; } public void addPlusPlus() {
number++; }
}
|
未加volatile关键字的DCL(Double Check Lock)存在的问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
|
public class LazyDoubleCheckSingleton { private volatile static LazyDoubleCheckSingleton lazySingleton=null;
private LazyDoubleCheckSingleton(){
}
public static LazyDoubleCheckSingleton getInstance(){ if(lazySingleton==null){ synchronized (LazyDoubleCheckSingleton.class){ if(lazySingleton==null){ lazySingleton=new LazyDoubleCheckSingleton();
} }
} return lazySingleton;
}
}
|
volatile底层