前面的偏向锁,轻量级锁,重量级锁都是悲观锁,
都会认为必须要对操作对象进行互斥访问,不然就会产生异常, 所以线程只供一个线程使用,阻塞其他线程,是悲观的
在某些情况下,同步的耗时远大于线程切换的时间,互斥就有点多余了
所以使用CAS compare ans swap
一个资源 对应一个 tig 为1表示被占用,0表示未被占用
两个线程(称为AB) 均想获取该资源,即都希望当前tig为0 并由自己将其置为1
用代码表示: 逻辑就是这样的
int cas(long* address,long oldValue,long newValue)
{
if(*address!=oldValue){
return 0;
}
*address = newValue;
return 1;
}
如果csa失败 则等待。
如果只看代码 同样也是无法实现互斥的,代在底层,我们的CAS 是原子性 的。比较和交换两个操作是一体的。
还有就是底层的循环等待一般也不是死循环,是有限制的
Java中的使用示例:
不使用CAS:
public class Main {
public static void main(String[] args) {
int i;
for (i = 0; i < 4; i++) {
new casTest().start();
}
}
}
class casTest extends Thread{
public static int a = 0;
@Override
public void run() {
while(a<1000){
System.out.println(getName() + " "+a++);
try {
sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
输出:
Thread-0 993
Thread-2 994
Thread-1 995
Thread-3 996
Thread-0 997
Thread-1 998----
Thread-2 998----
Thread-0 999
Thread-3 999
只截了最后几行
可以看到 标记处 两个线程输出了同样的数
代码线程不安全
下面我们尝试使用互斥锁
public class Main {
public static void main(String[] args) {
int i;
for (i = 0; i < 4; i++) {
new casTest().start();
}
}
}
class casTest extends Thread{
public static int a = 0;
@Override
public void run() {
while(a<1000){
System.out.println(getName() + " "+a++);
synchronized (Math.class){
a++;
}
}
}
}
输出:
Thread-2 982
Thread-2 984
Thread-2 986
Thread-2 988
Thread-2 990
Thread-2 992
Thread-2 994
Thread-2 996
Thread-2 998
Thread-1 502
Thread-0 586
无重复
下面我们用 CAS:
import java.util.concurrent.atomic.AtomicInteger;
public class Main {
public static void main(String[] args) {
int i;
for (i = 0; i < 4; i++) {
new casTest().start();
}
}
}
class casTest extends Thread{
// public static int a = 0;
public static AtomicInteger integer = new AtomicInteger(0);
@Override
public void run() {
while(integer.get()<1000){
System.out.println(getName() + " "+integer.incrementAndGet());
}
}
}
输出:
Thread-1 993
Thread-1 994
Thread-1 995
Thread-1 996
Thread-1 997
Thread-0 960
Thread-0 999
Thread-0 1000
Thread-2 943
Thread-1 998
顺序不同是因为输出的缘故
但不会出现重复,即实现了互斥
下面点进去看看源码:
确实用的是CAS
再往下一点:
这里是native方法
不同系统的代码可能不同,都是基于本地硬件进行CAS操作 c++实现
找到了一个源码的截图:
框框处调用了汇编命令