在对juc包不断升入的了解中,觉得有些基础知识不得不提,一个是CAS,还有一个在文档中常常数显的词语happen-before
CAS
CAS也就是campare and swap 的中文缩写,先比较再交换,她是一种乐观锁的实现方式,和synchronized
这种悲观锁的实现方式不一样,悲观锁一上来二话不说就先锁住,但是CAS觉得一般线程
是安全的,不上锁,但是会将当前线程获取的值和当前的值做一个比较,如果一样那么就更新,如果不一样,说明其它线程已经将值修改了,那么当前线程就更新值,因为更新也是需要时间的嘛,所以完之后
再和当前的值做比较,如此往复,那么这样的一个操作时通过自旋 volatile值实现的,CAS的基本操作在juc中体现在atomic
包中,其中有针对integer
、boolean
、long
、reference
的属性,数组等的操作,
基本满足项目中的需要,
刚才说的CAS基本实现就是通过自旋volatile值来实现的,具体又是如何实现的呢??
//AtomicInteger
private volatile int value;
public final int getAndSet(int newValue) {
return unsafe.getAndSetInt(this, valueOffset, newValue);
}
//unsafe
/**
*中间的var2是个固定的值,
* var1 是当前线程传进来的值,
* var5 是获取的 value在线程执行到这个地方来的时候的值,
* 会将var1 和var5 做比较,如果相同,那么就将 value值跟新到var4,
* 至于这一系列的操作都是在native方法中执行的
*/
public final int getAndSetInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var4));
return var5;
}
中间的var2是个固定的值,
var1 是当前线程传进来的值,
var5 是获取的 value在线程执行到这个地方来的时候的值,
会将var1 和var5 做比较,如果相同,那么就将 value值跟新到var4,
至于这一系列的操作都是在native方法中执行的
理解说明:
通过volatile和Unsafe提供的CAS函数实现原子操作。 自旋+CAS的无锁操作保证共享变量的线程安全
value是volatile类型,这保证了:当某线程修改value的值时,其他线程看到的value的值都是最新的值,即修改之后的volatile的值
通过CAS设置value。这保证了:某线程池通过CAS函数(如compareAndSet函数)设置value时,它的操作时原子性的,即线程在操作vu略时不会被中断。
但是这可能会出现另一个问题就是就是著名的ABA问题,那么Atomic包中是如何避免ABA问题的呢?或者说我们在想到ABA问题的时候,会想到什么方式来避免呢??
是的没错,就是用一个偏移量,每次对当前值修改的时候那么就+1操作,那么就能够很好的避免ABA问题!
在Atomic包中有这么两个类AtomicStampedReference
,AtomicMarkableReference
这两个类都是为了解决 ABA
问题的,但是AtomicStampedReference
是通过一个int类型在做偏移量,而AtomicMarkableReference
是通过一个boolean来做偏移量的
happen before
happen before 主要是针对于当前的JVM内存模型,为了提高执行效率,可能会对我们书写的代码进行重排序,但是某些情况下是不会冲排序的,也就是满足happen-before原则的代码
happen before 8原则
- 程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作;
- 锁定规则:在监视器锁上的解锁操作必须在同一个监视器上的加锁操作之前执行。
- volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作;
- 传递规则:如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C;
- 线程启动规则:Thread对象的start()方法先行发生于此线程的每一个动作;
- 线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生;
- 线程终结规则:线程中所有的操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行;
- 对象终结规则:一个对象的初始化完成先行发生于他的finalize()方法的开始;