并发编程学习笔记2

并发编程第3章,共享对象 synchonized不仅仅是将代码块声明成原子操作,而且管理的变量在内存中的可见性,保证其他代码看到的值是真实的值。应该是直接操作主存
3.1可见性
由于java内存模型的关系,变量的可见性也变的有些诡异。jmm有主存和本地存储的区别。当一个变量的值在本地存储中改变了,那么其他线程从主存中读取值时,很有可能是不能及时获取到最新的值的。这就是可见性。
锁可以实现这种可见性,同时保证操作的原子性
而volatile也可以实现内存变量的可见性,强迫所有线程获取变量的值都从主存中获取。但volatile不能实现操作的原子性。比如i++操作,即使i被声明为volatile,那么有可能出现以下情况:线程A读取主存获得到值4,然后i++.此时线程B也读取获得的值依然为4,然后也i++。那么最终AB执行完毕之后,最终的值被覆盖,应该为6的操作,却变成了5
所以使用volatile的时候,需要注意,满足以下情况,方可放心使用:
1.对一个变量的写操作,不依赖于其当前值(i++操作显然不满足),或者保证单线程
2.在一个不变体中,变量不参与其他状态的计算,或者说其他状态不依赖与此变量
3.在不需要锁的情况下
3.2发布对象和对象的逃逸
所谓发布对象,指将一些对象公开,使得其他代码可以访问到他,具体的方式有:将变量存储在一个类变量中,或者从一个非私有的方法中返回对象,或者通过参数传递给另一个类。
所谓对象的逃逸是指,比如我将对象A发布,但是由于A持有B的引用,那么B也被隐式的发布了,那么B就算是逃逸了
如果通过一个公共的方法将一些可变的值返回了,那么这是不安全的,因为可能有多个线程访问这个方法,并且有可能,某些线程会修改这个方法的返回值,由于引用的关系,那么方法的返回值就被人篡改了。其他线程获取的值,有可能就不是你想要暴露给外界的值了。从而引起问题。
另外也不要再一个对象构造完毕之前,将他暴露给外界,比如:在构造器中启动线程
3.3线程封闭
线程封闭就是将变量限制在当前执行线程之中,从而保证数据ok
3.4不可变对象
不可变对象:对象创建之后,对象状态不能改变;所有的字段均为final;被合理地构造(无this逃逸)
不可变对象和volatile的配合可以保证变量,能及时从主存获取数据,同时数据是最新的
3.5安全的发布对象
1.通过静态初始化器初始化对象;
2.将一个对象的引用声明为volatile或者AtomicReference
3.将一个对象的引用声明为final并保证该对象能正确初始化
4.将一个对象的引用存储到一个通过锁保护的field中
对于jdk提供的同步的集合类来说,有些特性javadoc并没有说明清楚,实际上,如果将对象扔进这些同步的集合当中,那么再次取出来的时候,对象就是线程安全的
有些对象本身可能并不是不变类,但是如果在使用当中,我们并不修改它的状态,那么可以认为他也是不变类,如Date类。
如何安全的共享对象:
1.线程封闭的。
2.只读共享
3.线程安全的共享--对象内部同步
4.通过锁保持同步

你可能感兴趣的:(jdk,编程)