volatile是Java虚拟机提供的轻量级同步机制
三大特性:1、保证可见性 2、不保证原子性 3、禁止指令重排
JMM你谈谈
JMM Java内存模型
JMM关于同步的规定:
1、线程解锁前,必须把共享变量的值刷新回主内存。
2、线程加锁前,必须读取主内存的最新值到自己的工作内存。
3、加锁解锁是同一把锁。
import java.util.concurrent.TimeUnit; class MyData { volatile int number=0; public void addTo60() { this.number=60; } } public class VolatileDemo { public static void main(String[] args) { MyData myData = new MyData(); new Thread(() -> { System.out.println(Thread.currentThread().getName()+"\t come in"); try { TimeUnit.SECONDS.sleep(3); }catch (InterruptedException e) { e.printStackTrace(); } myData.addTo60(); System.out.println(Thread.currentThread().getName()+"\t updated number value: "+myData.number); },"AAA").start(); while(myData.number==0) { } System.out.println(Thread.currentThread().getName()+"\t mission is over: "+myData.number); } }
volatile不保证原子性案例:
class MyData { volatile int number=0; public void addPlusPlus() { number++; } } 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<100; j++) { myData.addPlusPlus(); } },"BBB").start(); } while(Thread.activeCount()>2) { Thread.yield(); } } System.out.println(Thread.currentThread().getName()+"\t mission is over: "+myData.number); } }
结果输出1989,不是2000,所以说程序出现了问题。
那么如何解决原子性呢?
加synchronized?太重了
在包
package java.util.concurrent.atomic中
有Class AtomicInteger
import java.util.concurrent.atomic.*; class MyData { AtomicInteger atomicInteger = new AtomicInteger(); public void addAtomic() { atomicInteger.getAndIncrement(); } } 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<100; j++) { myData.addAtomic(); } },"BBB").start(); } while(Thread.activeCount()>2) { Thread.yield(); } System.out.println(Thread.currentThread().getName()+"\t mission is over: "+myData.atomicInteger); } }
为什么AtomicInteger可以解决原子性而不用加synchronized呢?
JMM:
1、可见性 2、原子性 3、有序性
有序性:
计算机在执行程序时,为了提高性能,编译器和处理器常常会对指令重排,一般分为以下3种:
源代码->编译器优化的重排->指令并行的重排->内存系统的重排->最终执行的指令
多线程环境中线程交替执行,由于编译器指令重排的存在,两个线程使用的变量能否保证一致性是无法确定的,结果无法预测。