操作系统中的锁
1.互斥锁
多个线程对临界资源的访问是互斥的,任何时刻只能有一个线程在执行临界区中的代码。
2.自旋锁
与互斥锁类似,唯一的区别在于互斥锁加锁失败后会让出CPU的执行权,但是自旋锁不会,它会进行一个忙等待,直到它拿到锁。
3.读写锁
多个线程可以同时进行读操作,但是写操作是独占的,就是当有线程在进行写操作时,其它线程既不能读也不能写。适用于多读少写的场景。
4.悲观锁
总是假设最坏的情况,访问共享资源前都会上锁。
5.乐观锁
总是假设最好的情况,访问共享资源前不会上锁,先修改完资源,当要提交时,判断共享资源有没有被其它线程修改过,如果没有则修改成功,否则放弃这次修改。一般基于版本号或CAS算法实现。
使用场景:修改时发生的冲突比较少,即写操作比较少,读操作比较多的时候可以使用乐观锁,如果写操作比较多的话就要使用悲观锁了。
补充:CAS算法
CAS算法:线程先获取对应内存地址中的数据,然后进行修改,当提交更新时,会检查当前内存地址中的数据和之前获取到的数据是否相同,如果相同则修改成功,否则放弃这次修改,重复这个过程直到修改成功。
ABA问题:假设我们需要修改某个数据A,当我们取出A后,有两个线程分别将A修改为B然后又将B修改为A,这会导致我们误以为
A没有被修改过,在一些场景下可能会出错。比如银行取款时,假设银行取款机发生错误发送了两个取款请求,其中一个线程取到账户余额后就阻塞了,另一个线程取款成功,但同时有人往账户上存钱导致余额出现A-B-A的变化情况,原先阻塞的另一个取款线程发现余额没有变化会再次取款,这样账户中就被扣了两次钱了。
可以通过再加一个版本号解决ABA问题。 线程安全之CAS机制详解