1.2.1线程安全之可见性问题
1.多线程中的问题
(1)所见非所得
(2)无法肉眼去检测程序的准确性
(3)不同的运行平台有不同的表现
(4)错误很难重现
2.问题
(1)从内存结构到内存模型
(2)工作内存缓存
(3)指令重排序
Java编程语言的语义允许编译器和微处理器执行优化,这些优化可以与不正确的同步代码交互,从而产生看似矛盾的行为。(不仅仅是Java级别,也是CPU级别;
内存屏障,不仅会调用jit,还会调用CPU的指令禁止重排序)
3.内存模型的含义
内存模型描述程序的可能行为。
【内存模型决定了线程在程序的每个点上可以读取什么值。】
4.Shared Variables共享变量描述
5.线程操作的定义
程序顺序:如果一个程序没有数据竞争,那么程序的所有执行看起来都是顺序一致的。
本规范只涉及到线程间(多线程)的操作。
6.对同步的规则定义(定义了读数据)
7.happens-before先行发生原则
当程序包含两个没有被happens-before关系排序的冲突访问时,就称存在【数据争用】。
遵守了这个原则,也就意味着有些代码不能进行重排序,有些数据不能缓存。
8.volatile关键字
9.final在jvm中的处理
10.Word Tearing字节处理
11.double 和long的特殊处理
1.2.2线程安全概念之原子操作
编译反编译查看class内容的命令 :java -p -v 名称
1.原子操作定义
【示例】
存在竞态条件线程不安全,需要转变为原子操作才能安全。方式:循环CAS、锁。
2.CAS机制
底层提供,针对变量级别,某一个属性或者某一个内存地址的操作。
实际应用中,不需要这么麻烦。因为Java为我们提供了一个J.U.C包内原子操作封装类。
三个问题
3.J.U.C包内原子操作封装类。
1.2.3锁的概念和synchronized关键字
1.Java中锁的概念
几种重要的锁实现方式:synchronized、 ReentrantLock、 ReentrantReadWriteLock
2.同步关键字synchronized
(1)概念
Java中每个对象都会有一个与之对应的监视器(object–mointor)
锁消除:如果没有什么竞争,就不应该用锁。
锁粗化:如果存在多个小范围的锁,可以变成一个大的锁。
同步关键字,不仅是实现同步,根据JVM规定还能保证可见性(读取最新主内存数据,结束后写入主内存)
(2)同步关键字加锁原理
3.偏向锁到轻量级锁
4.重量级锁-监视器(monitor)
修改mark word如果失败,会自旋CAS一定次数,该次数可以通过参数配置:
超过次数,仍未抢到锁,则锁升级为重量级锁,进入阻塞。
monitor也叫做管程,计算机系统原理中有提及类似的概念。一个对象会有一个对应的monitor。
1.2.4Lock锁接口实现
1.Lock的核心API
根据Lock的源码注释,Lock接口的实现,具备和同步关键字同样的内语义。
2.RenentrantLock
独享锁;支持公平锁、非公平锁两种模式;可重入锁;
重入的时候,加锁和解锁的次数要一致;有多少次lock就需要有多少次unlock。
3.ReadWriteLock
4.Condition
源码示例:
synchronized要了解
lock 要学会使用