第三章:对象的共享。
1:可见性
由于Java内存模型的原因,多线程之间对同一变量的读写操作可能无法实时的看到另一个线程的修改情况。使得多个线程之间对变量的修改操作并不是相互实时可见的。
为例保证可见性,虚的使用同步机制或者volatile关键字。
如果在工作内存中改变了变量,下一步应该是同步到主内存,但是由于两个不是原子性操作,在多线程情况下,这时候切换到另一个线程执行,这个线程在主内存获取到的值就是之前的值。既是失效数据
重排序:
重排序是指编译器和处理器为了优化程序性能而对指令序列进行重新排序的一种手段。当然不是所有指令都可以重排序,他们之间要没有因爱关系。
重排序也可能对指令的可见性产生影响。
失效数据:
一个线程修改了变量的值但是另一个线程读取到的值还是之前的。是因为可见性的原因而产生了失效数据。
2:保证可见性的方式
加锁可保证可见性:
有必要理解一下什么时候工作内存变量刷新到主内存,以及什么时候工作内存重新到工作内存请求变量跟新。链接
使用volatile时:
- 线程修改变量之后只能是同步到主内存中,原子操作
- 线程读取变量之前必须到主内存中同步,原子操作
- 不允许重排序
使得volatile使得线程键变量可见。
使用加锁机制(同步代码块)
- 变量解锁前必须同步到主内存
- 线程获取锁会同步主内存
保证同步代码块也可以保证可见性。
3:发布与溢出
发布:使对象可以在当前作用域之外的代码中使用
逸出:不该发布的对象被发布
4:线程封闭
**线程封闭:**将某个对象封闭在一个线程之中,即使这个对象线程不安全。仅在单线程中访问这个对象数据。 这种情况称为线程封闭。
4.1:Ad-hoc线程封闭
脆弱,一般不会使用
4.2:栈封闭
栈封闭中只有通过局部变量才能访问对象
因为局部变量固有的属性之一就是封闭在执行线程之中。位于执行线程的栈中,其他线程无法访问这个栈。
4.3:ThreadLocal类
***========
5:不变性
使用不可变对象也可以实现同步。
对象不可变条件:
- 对象创建后状态不能改变
- 对象的所有域都是final的
- 对象使正确创建的(没有this逸出)