SynchronizedBasicType.java
如何模拟死锁 public class DeadLock implements Runnable { int flag = 1; static Object o1 = new Object(); static Object o2 = new Object(); public static void main(String[] args) { DeadLock lock = new DeadLock(); DeadLock lock2 = new DeadLock(); lock.flag = 1; lock2.flag = 0; Thread t1 = new Thread(lock); Thread t2 = new Thread(lock2); t1.start(); t2.start(); } @Override public void run() { System.out.println("flag = " + flag); if (flag == 1) { synchronized (o2) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (o1) { System.out.println("1"); } } } if (flag == 0) { synchronized (o1) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (o2) { System.out.println("0"); } } } } } volatile保持线程之间的可见性(不保证操作的原子性),依赖这个MESI协议
防止指令重排序,CPU的load fence和store fence原语支持
CPU原来执行指令一步一步执行,现在是流水线执行,编译以后可能会产生指令的重排序,这样可以提高性能
DCL为什么一定要加volatile?DCL示例:
public class Singleton6 { private volatile static Singleton6 INSTANCE; private Singleton6() { } public static Singleton6 getInstance() { if (INSTANCE == null) { synchronized (Singleton6.class) { if (INSTANCE == null) { try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } INSTANCE = new Singleton6(); } } } return INSTANCE; } }在New对象的时候,编译完实际上是分了三步
对象申请内存,成员变量会被赋初始值
成员变量设为真实值
成员变量赋给对象
指令重排序可能会导致2和3进行指令重排,导致下一个线程拿到一个半初始化的对象,导致单例被破坏。所以DCL必须加Volitile
思维导图processon
源码Github
参考资料多线程与高并发-马士兵
实战Java高并发程序设计(第2版)
深入浅出Java多线程
Java并发编程实战
【并发编程】MESI--CPU缓存一致性协议
【并发编程】细说并发编程的三大特性
设计模式学习笔记