摘要: 并发访问共享资源,如果不加锁,可能会导致数据不统一问题,通常为了解决并发拜访问题,咱们都会在访问共享资源之前加锁,保障同一时刻只有一个线程拜访。上面咱们用问答的形式阐明下各种并发锁的概念、优缺点及其利用场景。
本文分享自华为云社区《一文带你全面了解各种锁机制》,原文作者:dayu_dls。
并发访问共享资源,如果不加锁,可能会导致数据不统一问题,通常为了解决并发拜访问题,咱们都会在访问共享资源之前加锁,保障同一时刻只有一个线程拜访。上面咱们用问答的形式阐明下各种并发锁的概念、优缺点及其利用场景。
1、什么是互斥锁和自旋锁,各有什么优缺点?
互斥锁和自旋锁是最底层的两种锁,其余的很多锁都是基于他们的实现。当线程 A 获取到锁后,线程 B 再去获取锁,有两种解决形式,第一种是线程 B 循环的去尝试获取锁,直到获取胜利为止即自旋锁,另一种是线程 B 放弃获取锁,在锁闲暇时,期待被唤醒,即互斥锁。
互斥锁会开释以后线程的 cpu,导致加锁的代码阻塞,直到线程再次被唤醒。互斥锁加锁失败时,会从用户态陷入到内核态,让内核帮咱们切换线程,存在肯定的性能开销。
- (1)当线程加锁失败,内核会把线程的状态由“运行”设置为“睡眠”,让出 cpu;
- (2)当锁闲暇时,内核唤醒线程,状态设置为“就绪”,获取 cpu 执行;
而自旋锁会自用户态由应用程序实现,不波及用户态到内核态的转化,没有线程上下文切换,性能绝对较好。自旋锁加锁过程:
- (1)查看锁的状态;
- (2)锁闲暇,获取锁,否则执行 (1);
自旋锁会利用 cpu 始终工作直到获取到锁,两头不会开释 cpu,但如果被锁住的代码执行工夫较长,导致 cpu 空转,浪费资源。
2、什么是读写锁?
读写锁由读锁和写锁组成。读锁又称为共享锁,S 锁,写锁又称为排它锁、X 锁,在 mysql 的事务中大量应用。写锁是独占锁,一旦线程获取写锁,其余线程不能获取写锁和读锁。
读锁是共享锁,当线程获取读锁,其余线程能够获取读锁不能获取写锁。因为并发数据读取并不会扭转共享数据导致数据不统一。读写锁把对共享资源的读操作和写操作别离加锁管制,可能进步读线程的并发性,实用于读多写少的场景。
3、什么是读优先锁、写优先锁、偏心读写锁?
读优先锁心愿的是读锁可能被更多的线程获取,能够进步读线程的并发性。线程 A 获取了读锁,线程 B 想获取写锁,此时会被阻塞,线程 c 能够持续获取读锁,直到 A 和 c 开释锁,线程 B 才能够获取写锁。如果有很多线程获取读锁,且加锁的代码执行工夫很长,就到导致线程 B 永远获取不到写锁。
写优先锁心愿的是写锁可能被优先获取。线程 A 获取了读锁,线程 B 想获取写锁,此时会被阻塞,前面获取读锁都会失败,线程 A 开释锁,线程 B 能够获取写锁,其余获取读锁的线程阻塞。如果有很多写线程获取写锁,且加锁的代码执行工夫很长,就到导致读线程永远获取不到读锁。
下面两种锁都会造成【饥饿】景象,为解决这种问题,能够减少一个队列,把获取锁的线程(不论是写线程还是读线程)依照先进先出的形式排队,每次从队列中取出一个线程获取锁,这种获取锁的形式是偏心的。
4、什么是乐观锁和乐观锁?
乐观锁是先批改共享资源,再用历史数据和以后数据比对验证这段时间共享数据有没有被批改,如果没有被批改,那么更新数据,如果有其余线程更新了共享资源,须要从新获取数据,再更新,验证,周而复始的重试,直到更新胜利。所以当数据更新操作比拟频繁,数据抵触的概率就会比拟大,重试的次数就会多,节约 CPU 资源。
乐观锁其实全程没有加锁,也叫无锁编程,所以针对读多写少的场景,并发性能较高,典型的实现 MVCC,mysql 中会应用 MVCC 构建一致性读来保障可反复读。乐观锁是在访问共享资源之前通通加锁。当并发抵触概率较高时,乐观锁不在实用,乐观锁就排上用场。互斥锁、自旋锁都是乐观锁的实现。
点击关注,第一工夫理解华为云陈腐技术~