当线程用synchronize锁的时候,可以保证线程是具有原子性 可见性 有序性的。
原子性,
表现为每个可以单独操作,不互相依赖,在线程中表现为每个线程都有所以它自己的一份copy值,不定期的刷新到主内存。(如果有锁,ulock时刷新到主内存)
而volatile变量不具有原子性,每次读写都是自己去主内存读主内存的值,也真是由于此种原因不能进行计数器操作,例如:
volatile i =1;
线程A,线程B 同时 i++;
i++ 即
i=i; //从主内存中读 1
i+1; //通过获取的值。计算 2
i=i+1; //把计算的值写入主内存中 3
当线程执行顺序如下时 A1 – >B1—>A2—>A3—>A1—>B2—>B3, 最后结果导致运行了两次结果还是2
对此,
1, 可以用CAS算法进行改进
CAS也可成为乐观锁,实现原理,通过保存原有值进行比较结果,直到更改成功
实现原理,CAS保存了3个值 H当前值(作为预期值),V内存值,S计算值
代码实现如下
public final int casTest() {
for (;;) {
int
h=i; //A线程叫AH,B线程描述为BH 1
int s = i +
1; // A线程叫AS,B线程描述为BS 2
if(h==i){ // 比较内存值和预期值 3
i=s; // 如果相同,赋值,成功CAS 4
break;
}
}
A1 (A开始时用AH保存内存中此时的i值)->
B1(B开始时也用BH保存当前i值)->
A2 (把计算值2赋给AS)
A3(比较保存的AH和读取内存值AV,都是等于1,未改变)
A4(所以CAS成功,把AS即2放入内存中)
B2(把计算值2赋给BS)
B3(比较BH和读取当前内存值BV,BH是1,BV是2,所以不相等,返回到B1)
B1 (故重新取出内存值i,重复计算,此时BH=BV=2,BS=3赋给主内存,完成计数)
其实在并发包中的实现原理我也差不多(待考证……),只是用的是native方法,看代码
/**
* Atomically sets to the given value and returns the old
value.
*
* @param newValue the new value
* @return the previous
value
*/
public final int getAndSet(int newValue) {
for (;;)
{
int current = get(); // step 1
if
(compareAndSet(current, newValue)) //step 2
return
current;
}
}
step1 相当于获取当前值h,并保存
step2 newValue相当于比较s,计算值
2, 当然可以用synchronize锁进行同步(略)