CAS和synchronized都是解决线程安全问题的一种方法,CAS相较于synchronized实现了无锁化编程,而synchronized就是我们常说的加锁,虽然两种方法都可以解决线程安全问题,但是CAS更加简便。
1.锁升级 synchronized优化过程:synchronized的优化过程分为几步,刚开始会处于“偏向锁”状态,之后由于锁竞争会升级到“轻量级锁”,在之后通过进一步统计锁冲突出现次数升级到“重量级锁”。这种方式也可以称为锁升级,但这种升级是不可逆的,比如重量级锁不会在编程轻量级锁。
我们着重介绍一下“偏向锁”,偏向锁只是一种状态,它不属于锁,只是一种状态或者说姿只是进行一下标记,这种状态的好处就在于,当一个线程获取锁时,这个请求会被记录下来但是并不会立即上锁,如果后续有必要用到是才会进行上锁,这样的好处就在于可以减少线程中的竞争,提高性能。
2.锁清除 编译器会对你的synchronized代码判断是否需要加锁,如果不需要加锁,编译器就会自动把synchronized干掉。锁消除虽然存在但是我们在日常中不能完全靠这个无脑加锁。
3.锁粗化
锁粗化就是把多个细粒度的锁变为粗粒度的锁。
代码越多就是粒度越粗,代码越少就是粒度越少。
CAS 全程compare and swap 比较内存和寄存器中的内容如果相同则进行交换,比如内存和寄存器一进行比较发现值是相同的,此时将寄存器二的值赋值给内存,我们没有必要了解,寄存器二中的内容是什么这里只是单纯的交换。
CAS的java伪代码如图:
public synchronized boolean compareAndSet(int expectedValue, int newValue) {
if (value == expectedValue) {
value = newValue;
return true;
} else {
return false;
}
}
这里的value就是内存中的值,expectedValue和newValue可分别看成寄存一和寄存器二中的值,第一个if判断内存中的值现在是否和刚才寄存器一再内存中取出的值相同(也就是expectedValue,这里主要是为了避免线程安全问题中的内存可见性问题,由于线程的穿插执行所导致的),如果相等说明此时没有其他线程在穿插执行,可以将内存中的值修改为我们想要改的值newValue,如果判断此时value不等于expectedValue说明此时有其他线程进行穿插执行,此时不修改内存中的值也就是value返回false。通过这种方式我们就没有必要进行加锁了,也就是我们所说的无锁化编程。