Java中的锁

锁的分类如下:

  公平锁和非公平锁

  重入锁

  独享锁和共享锁

  互斥锁和读写锁

  乐观锁和悲观锁

  分段锁

  自旋锁

  偏向锁和轻量级锁和重量级锁

 锁的概念就不详细说明了。直接开始介绍这几种锁

  公平锁和非公平锁

  如同名字的意思,公平锁在多线程等待同一个锁的时候必须按照申请锁的时间顺序来依次获得锁;而非公平锁则不是这样。Java中synchronized中的锁是非公平的,而ReentrantLock默认情况下是非公平的,但是可以通过构造函数要求使用公平锁。源码中的构造方法如下

  

public ReentrantLock() {
        sync = new NonfairSync();
    }
  
public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
}

  重入锁

  又叫递归锁,大概意思就是当线程获取锁后递归调用自身的时候仍然可以进入。ReentrantLock和synchronized都具备线程重入的特性

  独占锁和共享锁

  又如名字,独占锁只能被一个线程占有,而共享锁则可以多个线程共享。典型的共享锁有ReadWriteLock接口的实现类ReentrantReadWriteLock。其读锁为共享锁,写锁为独占锁又或者称为排他锁

  互斥锁和读写锁同上,意思大概相同

  乐观锁和悲观锁

  概念意义上的锁,悲观锁就是悲观,每次拿数据都认为别的线程会修改数据,所以每次拿都上锁,适用写操作比较多的时候。乐观锁,认为不加锁的并发操作没有事情。针对数据库而言,悲观锁可通过对Sql语句加上 for update 上锁,效率较低。乐观锁则可以为数据表添加一个version字段,保存更新记录。

  自旋锁

  Java中线程的操作都需要通过操作系统来帮忙,因此需要从用户态转换到核心态中,因此需要耗费很多时间。自旋锁则通过短时间的忙循环等待,避免了线程的挂起和恢复。当然自旋的次数过多也会占用cpu资源。自旋次数默认为10次。JDK1.6之后还引入了自适应的自旋锁。由前一次在同一个锁自旋的时间和拥有者的状态来决定。如果刚刚自旋并获得锁,则认为其可能再次成功,就多自旋几次。如果很少成功,则可能省略掉自旋的过程。

  偏向锁和轻量级锁和重量级锁

  synchronized就是一个重量级锁。之所以提出轻量级锁,自旋锁,偏向锁的根本目的就是为了提高锁的性能。轻量级锁的本意实在没有多线程竞争的情况下,通过CAS算法减少传统重量级锁使用操作系统互斥量产生的性能消耗。而偏向锁则是如果该锁没有被其他线程获取的时候,持有偏向锁的线程永远不需要进行同步。

  分段锁详细见jdk1.8以前的ConcurrentHashMap

原文地址:https://www.cnblogs.com/helloDuo/p/9404110.html