转载自:https://baijiahao.baidu.com/s?id=1697365218983521838&wfr=spider&for=pc
我们在工作中,不知你是否留意java的一些锁,什么乐观锁、悲观锁、自旋锁、可重入锁、读写锁、公平锁、非公平锁、共享锁、独占锁、重量级锁、轻量级锁、偏向锁、分段锁、互斥锁、同步锁、死锁、以及锁粗化和锁消除。
乐观锁
是一种乐观思想,假设当前业务读多写少,遇到并发写的概率比较低,读数据时候认为别的线程不会对数据进行修改,所以没有上锁。写数据时候,判断当前与期望的值是否相同,如果相同则进行更新,java中的乐观锁主要用到cas的比较并替换,比较预期值和当前值是否一样,一样则更新,否则进行cas操作。
悲观锁
悲观锁是一种悲观思想,即认为写多读少,遇到并发写的可能性高,每次进行业务修改的时候,都会认为其它业务操作会对数据进行修改,所以每次读写数据的时候就会上锁。
自旋锁
自旋锁属于一种技术,为了让线程等待,只需让线程来执行一个循环,但不放弃处理器的执行时间,看看持有锁的线程是否很快就会释放锁。
可重入锁
可重入锁也是一种技术,任意线程在获取锁之后,能够再次获取锁,而不会被锁所排斥。
读写锁
这个很好理解,当一个读线程来的时候,会首先判断这个锁是否是被写锁持有,如果当前线程也不是带有写锁的线程,那么就会返回负一,即获取锁失败,当前线程会被放入等待队列里面等待。如果当前线程是写锁或者锁没被其它线程所持有,那么当前读就可以获取读锁。
公平锁和非公平锁
何谓公平,就是线程来的时候公平对待,严格的按照顺序。
非公平就不按照锁的顺序了,有可能后申请的锁比先进入的锁更先获取锁,在高并发情况下。
共享锁
又称读锁,若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。
独占锁
多占锁顾名思义,每次只有一个线程持有锁。
重量级锁、轻量级锁偏向锁
如果实际上没有锁竞争,那么竞争的锁就会一直等待,我们引入轻量级锁来降低线程之间切换的成本。
在JDK 1.6之前,监视器锁可以认为直接对应底层操作系统中的互斥量(mutex)。这种同步方式的成本非常高,包括系统调用引起的内核态与用户态切换、线程阻塞造成的线程切换等。因此,后来称这种锁为“重量级锁”。
在没有实际竞争的情况下,还能够针对部分场景继续优化。如果不仅仅没有实际竞争,自始至终,使用锁的线程都只有一个,那么,维护轻量级锁都是浪费的。偏向锁的目标是,减少无竞争且只有一个线程使用锁的情况下,使用轻量级锁产生的性能消耗。轻量级锁每次申请、释放锁都至少需要一次CAS,但偏向锁只有初始化时需要一次CAS。
分段锁
是把一个激烈竞争的锁分为多个锁,这多个锁存在激烈的竞争。
互斥锁
在编程中,之所以存在互斥锁是因为为了保证数据的完整性,使得每个对象都有一个互斥锁的标记。
同步锁
同步锁是为了保证每个线程都能正常执行原子不可更改操作。
死锁
死锁是指两个线程互相持有对方的锁,而彼此不释放。
锁粗化和锁消除
锁消除是多此一举的加锁,代码片本事不会因为资源共享而发生冲突,而锁粗化顾名思义是增大加锁范围,在某一些情况下,我们希望把多次加锁合并成一次,避免反复的加锁降低性能,锁的申请和释放本身会带来性能损耗