锁大家都知道吧,多线程访问资源会存在竞争,那么就需要加锁进而让多个线程一个一个访问。
比如有一个房间,一次只能进一个人,现在有十个人都想进去怎么办?
对,加锁。拿一把钥匙,谁抢到钥匙谁就进去,出来后再把钥匙给到剩余的人来竞争
悲观锁:顾名思义,我比较悲观,认为每次访问都会发生竞争,所以需要加锁来保证不会发生竞争。
就像上面10个人总是一起进这个房间。
乐观锁:顾名思义,我很乐观,认为多个线程不会发生竞争,所以就不需要加锁。
就像上面10个人分别在1点到10点来,在房间只呆3分钟就走了,那么就没必要加锁。
那么这个是否会发生竞争,如果鉴别呢? 下面CAS登场了
cas = compare and swap,比较然后再交换。cas 是一个乐观锁
cas涉及到三个变量
- v 要修改的变量,是全局的
- e 期望修改前变量的值
- n 期望修改后的值
比如线程A要对变量V进行修改,首先执行e = get(v),获取变量当前的值,然后执行cas(v,e,n) 这个原子操作。此操作会比较v=e是否成立,如果成立表明没有发生竞争,可以修改变量,如果不成立表明v被修改了,发生了冲突,所以会停止修改。
我们知道e ≠ v 很明显是v被其他线程修改了,发生了竞争。 那么e = v就表明没发生竞争么?
答案显然不是,如果另一个线程将v++ 然后又v— 是不是e = v仍然成立?这个被称作ABA问题
怎么办? 可以对每个变量v附带加上一个时间戳,每次比较时除了比较e = v 再加上一个 etimestamp = vtimestamp即可
当然也有别的版本是新增一个version, 每次修改version++, 然后比较vversion = eversion即可
完整流程如下: