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种:
源代码->编译器优化的重排->指令并行的重排->内存系统的重排->最终执行的指令

多线程环境中线程交替执行,由于编译器指令重排的存在,两个线程使用的变量能否保证一致性是无法确定的,结果无法预测。