Java多线程学习笔记 (6)

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缓存一致性协议

【并发编程】细说并发编程的三大特性

设计模式学习笔记

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wppdzy.html