1.05.01-本章总结
本章探讨可见性和有序性
2.05.02-可见性-问题
3.05.03-可见性-解决
4.05.04-可见性vs原子性
因为sout底层使用了synchronized()同步代码块
记得这里不能保证原子性
5.05.05-设计模式-两阶段终止-volatile
之前用isinterrupted实现两阶段终止!!!
使用volitate改进:
一个线程对变量的修改对另一线程可见
6.05.06-设计模式-犹豫模式
犹豫模式,别人做了我就不做了
停止可以使用volitate,但是start得用synchronized
总结:volitate只能适用于那些只有一个写线程
7.05.07-设计模式-犹豫模式-应用
用于监控功能
但是synchronized三种都能解决,非常重要!!!:可见性,同步性,有序性
synchronized:同步代码块!!!可以保证同步性
懒惰初始化!!!
8.05.08-有序性-指令重排
9.05.09-有序性-指令重排原理-指令并行优化
实现指令级的并行,注意看!!!
10.05.10-有序性-指令重排-问题
11.05.11-有序性-指令重排-验证
12.05.12-有序性-指令重排-禁用
13.05.13-volidate-原理-保证可见性
读屏障->同步
写屏障->读的是主存
14.05.14-volidate-原理-保证可序性
注意这些不能解决指令交错,也就是另一个线程的修改
也就是不能解决原子性
但是synchronized三种都能解决,非常重要!!!:可见性,同步性,有序性
synchronized:同步代码块!!!可以保证同步性
15.05.15-volidate-dcl-简介
懒惰实例化:用到时才加速
锁的粒度有点大
做两次判断:
16.05.16-volidate-dcl-问题分析
有问题:第一个if没在synchronized中,会有有序性的问题
此时还没有调用构造方法,但是已经发生了赋值,所以现在赋值的是null
产生指令交错了!!!
17.05.17-volidate-dcl-问题纠正
注意:!!!synchronized 只能保证临界区内的指令不会和临界区外的指令发生重排序
synchronized中的指令仍然是可以被重排序的
如果共享变量完全被synchronized所保护,就不会有原子,有序,可见三方面问题
同步代码块的开始和结尾都是加了读写屏障,因此,外面的指令不能重排序到代码块里面来,代码块里面的指令也不能从排序到代码块外面去,但是代码块里面的代码的重排序是不受读写屏障保护的,还是可以发生重排序
这里是因为在synchronized外面也有对共享变量的修改
18.05.18-volidate-dcl-问题解决
用volitate解决重排序问题
这题里面构造方法不能排在写屏障后面!!!
使用读写屏障!!!
通过写屏障阻止指令的重排序!!!
读屏障会保证在读屏障之后的不会跑到读屏障之前
防止之前的代码跑到后面去:
v olitale是在1.5后正式生效!!!
写和读的时候才加入屏障
19.05.19-happens-before规则
默认值是指:类加载过程中,准备阶段,赋的默认值
写屏障之前的操作全部屏蔽在写之前
20.05.20-习题-balking模式
有问题,不能保证原子性,只能保证可见性和有序性,这里有原子性问题
21.05.21-习题-线程安全单例1
1.怕将来有子类,子类覆盖父类中的方法
2.加个readResolve,直接返回已有的对象,不会产生新的对象
3.不能,还是有其他方法
4.静态成员变量类加载过程,能保证
5.使用public的好处:在返回结果前,对其做一些自定义的处理
比如可以把他变成懒汉式,懒汉式天生线程安全
饿汉式依靠类加载时的clinit静态初始化时执行,保证了线程安全,但对内存不友好
22.05.22-习题-线程安全单例2~4
1.定义时有几个就有几个
2.也没有,也是静态成员变量
3.不能
4.枚举类默认实现序列化接口,但是不能被破坏单例
5.枚举属于超级饿汉式,上一个也是饿汉式,在一开始就初始化了
6.写一些构造方法
能用枚举用枚举 不能用枚举能饿汉就饿汉 最后考虑懒汉
线程安全,锁的范围有点大,性能低
1.重排序!!!
synchronized里面的指令还是会重排序的
防止多线程访问构造方法时的指令重排序导致的破坏单例问题
2.提高性能
3.防止第一次并发创建的,不要被同步创建!!!
double checked locking
DCL
23.05.23-习题-线程安全单例5
1.懒汉式,内部类,jvm保证了类加载只加载一次,所以内部类也只加载一次
2.内部类由jvm保证安全性
24.05.24-习题-第五章小结