Volatile三大特性
保证可见性
/**
* volatile可见性
* @Author Weton Li
* @Date 2021/2/11 22:11
*/
public class JMMdemo1 {
// 若不使用volatile,程序会死循环
private volatile static int num = 0; // 保证volatile可见性
public static void main(String[] args) {
new Thread(()->{
// 线程1对主内存的变化不知晓,需给num加volatile,显示可见性
while (num == 0) {
}
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
num =1;
System.out.println(num);
}
}
不保证原子性
/**
* volatile不保证原子性,在方法中加锁
* 若不用锁,如何保证原子性
* @Author Weton Li
* @Date 2021/2/12 09:55
*/
public class JMMdemo2 {
// private volatile static int num = 0;
private static AtomicInteger num = new AtomicInteger(); // 原子包装类,底层使用CAS
public /*synchronized*/ static void add(){
// num++;
num.incrementAndGet(); // 在内存中修改值,而不是num++。类的底层直接和操作系统挂钩,Unsafe类是特殊的存在
}
public static void main(String[] args) {
for (int i = 1; i <= 20; i++) {
new Thread(()->{
for (int j = 0; j < 1000; j++) {
add();
}
}).start();
}
while (Thread.activeCount() > 2) {
Thread.yield();
}
System.out.println(Thread.currentThread().getName()+"->"+num);
}
}
禁止指令重排
在逻辑问题上产生,但在实际运行中基本不会发生
内存屏障,CPU指令。作用:保证特定的操作的执行顺序。保证某些变量的内存可见性。
单例模式
/**
* 懒汉式
*
* @Author Weton Li
* @Date 2021/2/12 11:07
*/
public class Lazy {
// 红绿灯
private static boolean qinjiang = false;
private Lazy(){
synchronized (Lazy.class){
if (qinjiang == false){
qinjiang = true;
}else {
// if (lazy != null) {
throw new RuntimeException("不要试图使用反射破坏异常");
// }
}
}
System.out.println(Thread.currentThread().getName()+"->ok");
}
private volatile static Lazy lazy;
/**
* 双重检测锁模式,DCL懒汉式,加原子性操作,使用volatile防止指令重排现象发生
* @return
*/
public /*synchronized*/ static Lazy getInstance(){
if (lazy == null) {
synchronized (Lazy.class){
if (lazy == null) {
lazy = new Lazy(); // 不是原子性操作
/**
* 1.分配内存空间
* 2.执行构造方法,初始化对象
* 3.把对象指向这个空间
* 如果发生指令重排132,A线程没问题,B认为lazy!=null完蛋。
*/
}
}
}
return lazy;
}
public static void main(String[] args) throws Exception {
Field qinjiang = Lazy.class.getDeclaredField("qinjiang");
qinjiang.setAccessible(true);
// for (int i = 1; i <= 10 ; i++) {
// new Thread(()->{
// Lazy.getInstance();
// }).start();
// }
// Lazy lazy1 = Lazy.getInstance();
Constructor<Lazy> declaredConstructor = Lazy.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true); // 无视私有构造器
Lazy lazy1 = declaredConstructor.newInstance();
qinjiang.set(lazy1,false); // 道高一尺魔高一丈,又被改回来了
Lazy lazy2 = declaredConstructor.newInstance();
System.out.println(lazy1+"/"+lazy2); // 不同
}
}