本人曾接手过一些很奇怪的代码,基本到处都是是volatile和硬加锁,说是为了安全,就不怕死锁和性能太差吗?其实我压根不想改这种东西了,既然能过code review那么说明什么问题了?我不会让自己成为这类人。
参考自
乐观锁和悲观锁
简单解释就是,悲观锁认为在一个线程使用数据的时候,一定会有别的线程来修改数据,所以在使用数据时候就加上一个锁,synchronizied和lock就是如此。
乐观锁是一种使用不直接加锁,当修改时再判断数据是否被其他线程修改之类的无锁编程。CAS,你不需要手动设置锁。
CAS很简单,只讲缺点
ABA问题
循环开销大
只能保证一个原子量
自选锁和适应性自旋锁
因为自旋锁缺点比较明显,就是cpu一直再切换,因此有了适应性自旋锁
自选等待实际上只是减少cpu的切换性能浪费,将线程挂起也是占用着cpu的资源,因此现在为了避免过度等待也有不同的等待策略。
无锁,偏向锁,轻量级锁,重量级锁
上面我们介绍的CAS原理及应用即是无锁的实现。无锁无法全面代替有锁,但无锁在某些场合下的性能是非常高的。
偏向锁是指一段同步代码一直被一个线程所访问,那么该线程会自动获取锁,降低获取锁的代价。
在大多数情况下,锁总是由同一线程多次获得,不存在多线程竞争,所以出现了偏向锁。其目标就是在只有一个线程执行同步代码块时能够提高性能。
是指当锁是偏向锁的时候,被另外的线程所访问,偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,不会阻塞,从而提高性能。
若当前只有一个等待线程,则该线程通过自旋进行等待。但是当自旋超过一定的次数,或者一个线程在持有锁,一个在自旋,又有第三个来访时,轻量级锁升级为重量级锁。
公平锁和非公平锁
可重入锁和不可重入锁
当线程尝试获取锁时,可重入锁先尝试获取并更新status值,如果status == 0表示没有其他线程在执行同步代码,则把status置为1,当前线程开始执行。如果status != 0,则判断当前线程是否是获取到这个锁的线程,如果是的话执行status+1,且当前线程可以再次获取锁。而非可重入锁是直接去获取并尝试更新当前status的值,如果status != 0的话会导致其获取锁失败,当前线程阻塞。
独享锁和共享锁
ReentrantLock虽然有公平锁和非公平锁两种,但是它们添加的都是独享锁。根据源码所示,当某一个线程调用lock方法获取锁时,如果同步资源没有被其他线程锁住,那么当前线程在使用CAS更新state成功后就会成功抢占该资源。而如果公共资源被占用且不是被当前线程占用,那么就会加锁失败。所以可以确定ReentrantLock无论读操作还是写操作,添加的锁都是都是独享锁。