-
volatile
-
保证线程可见性
- java有堆内存,大家共享堆内存,当然每个线程也有自己的工作空间,当需要数据的时候copy到自己的工作空间,如果修改了会出现与堆数据不一致,就就是说对公共数据的更改另一个线程不可见,如果加上volatile,就是强制每次访问数据都会被强制推回堆,底层是cpu的缓存一致性协议保证的
-
禁止指令重排序
-
什么是指令重排序?
- 是cpu为了提高速率将指令进行了重排序,效率提升了很高
-
volatile会涉及到经典的单例问题
//饿汉 public class single{ //static数据交给jvm初始化,静态变量只会new出一个实例 private static final single INSTANCE=new single(); //防止外界new private single(){} public static single getInstance(){ return INSTANCE; } } //懒汉-线程不安全 public class single{ //static数据交给jvm初始化,静态变量只会new出一个实例 private static single INSTANCE; //防止外界new private single(){} public static single getInstance(){ if(INSTANCE==null){ INSTANCE=new single(); } return INSTANCE; } } //DCL-线程安全 public class single{ //static数据交给jvm初始化,静态变量只会new出一个实例 private static volatile single INSTANCE; //防止外界new private single(){} public static single getInstance(){ if(INSTANCE==null){ synchronized(this.class){ if(INSTANCE==null){ INSTANCE=new single(); } } } return INSTANCE; } }
-
为什么DCL要加volatile,问题出现在
INSTANCE=new single();
这句指令new一个对象分为三步
- 第一步是申请内存大小,并且会赋一个初始值
- 第二步赋上真正的值
- 第三步把内存的东西指向引用名INSTANCE
如果超高的并发情况下,指令重排发生把第三步挪到了第二步,如果线程A执行了一三步,这时INSTANCE不为空但是值不正确,另一个线程同时进入判断INSTANCE不为空直接拿去用了,这就出现了错误
volatile保证了有序性和可见性,但是不能保证原子性,所以说他不能替代synchronized
锁细化和锁粗化,细化是尽量把加锁的代码片段缩小,那什么时候用锁粗化?就是如果一个对象被分成了好多小锁,这样加锁频繁,不如粗化成大锁
-
-
-
-
CAS(无锁优化,自旋,乐观锁)Compare And Set
- AtomicXXX都是线程安全的原子类
/*volatile int count=0*/ AtomicInteger count=new AtomicInteger(0); /*synchronized*/void m(){ for(int i=0;i<1000;i++){ count.incrementAndGet(); /*count++*/ } }
count.incrementAndGet();
底层就是Unsafe的weakCompareAndSet()
方法cas(V,Expected,NewValue){ if V==E V==NewValue; otherwise try again or fail }
-
如果在if判断过程中出现把V给改了怎么办?
CAS是CPU原语支持,不会存在这种情况
-
ABA问题?
- CAS期望是A,在CAS没操作的时候,另一个线程先改成了B又改成了A
- 对于基础数据类型似乎没有影响,但是如果是对象呢?
- 由于对象判断的是引用地址是否改变,而里面的内容是不知道的,如果在对象指向B的时候,B的代码对A对象里的内部进行了修改,那么当在置换为A的时候,cas仍然认为A没有发生任何变化,只是因为他判断的是引用,指向的确实是A,就比如和前女友复合的过程,你不知道前女友在符合之前又经历了多少个男人,但是前女友还是那个人
- 解决办法加版本号CAS(version),可以用AtomicStampedReference解决(知道就行)
-
简单看看Unsafe
- 所有原子类都是通过unsafe的CAS实现的
- 用来分配内存的,类似于malloc
- unsafe类是单例的
- 1.8版本Unsafe不能获取,,而1.9版本可以get拿到,之前可以反射获取,但是现在1.9版本即使获取,代码能写出来,也运行不了,应该是作为内部api了,把这个接口给关了
多线程与高并发编程(二)
最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...