三大特性 原子、有序、可见
·1、从JMM内存模型来说,工作内存和主内存之间的数据同步需要靠volatile去保障可见性。确保访问时能从主内存中获取。
2、由于jvm指令重排导致的多线程访问时,产生数据不一致问题。例如:Object o = new Object()。对象创建过程中,将Objeict内存引用赋值给o和Object对象初始化赋值这两步就可能发生重排。试想象在多线程环境下,因指令重排,有线程将Objeict内存引用赋值给o,然后其他线程抢占到cpu,运行程序,此时发现o已经不为null,就去使用,而此时o实际还没有初始化完成。当再切回之前的线程后,继续完成初始化赋值,那么对于其他线程o的成员变量属性是变化的。
拿双重校验锁单例模式来讲:
synchronized虽然能保证synchronized中的代码能够在某个线程中执行完,再被其他线程访问,但是不能保证synchronized中的代码在执行时,其他线程访问单例对象。如果单例对象的创建发生指令重排,即使加了synchronized,那么在重排过程中,对单例对象的访问还是线程不安全的。
一旦我们加上volitate,避免了指令重排,那么就等于保证了在synchronized过程中,其他线程对单例对象的访问时,要么是null,要么就是初始化完成的对象。而不会说先拿到未初始化的对象,后又拿到已经初始化的对象。
public class Singleton {
private volatile static Singleton instance;
public static Singleton getInstance() {
if (instance == null) {//避免指令重排后,这里访问单例对象要么是null继续等锁释放。要么就是初始化完成的对象return。
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
3、原子性,保证一段代码的执行是原子的,通常加锁实现,加锁后也就是一个线程访问锁中的代码时,其他线程需要阻塞等待锁释放
待完善...