「并发」公平锁、非公平锁、重入锁

52 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第7天,点击查看活动详情

公平锁和非公平锁

原理举例

公平锁:多个线程对锁的竞争是差不多公平的

A执行了20次,B执行了19次,C执行了19次

特点:各个线程都会有执行的可能,但是效率相对于较低

实现逻辑:其中有个方法将多个线程放入队列中进行排队执行

非公平锁

多个线程对锁竞争是不公平的

A执行20次,B执行0次,C执行1次

特点:锁的竞争很不公平,但是执行的效率较高

实现逻辑:直接进行业务执行,哪个线程能竞争到锁随意

new ReentrantLock()的构造方法中可以传入boolean参数,false(默认)表示非公平锁

公平锁优缺点

优点:不会出现有的线程被饿死的情况

缺点:效率相对于而言低一些。需要不停的唤醒阻塞线程

公平锁实现

通过维护一个线程的队列。每次获取锁必须是排队的第一个,释放锁之后就自动去队列末尾继续排队等待

可重入锁和非可重入锁

概念和实例

递归锁:一个线程在外层获取到锁之后进入内层会自动获取锁(锁的对象是同一个)。

public void static main(String[] args){
  synchronized (this){
     //xxxxx
    synchronized(this){
      //xxxxx
    }
  }
}

锁的内部如果还有锁,该线程都可以访问。也就是多重锁,只要线程竞争到了锁资源,就可以访问到最内部也不用再重新竞争锁

synchronized是隐式的可重入锁

ReentrantLock是显式(需要手动上锁和解锁)的可重入锁

NonReentrantLock不可重入锁。

ReentrantLock和NonReentrantLock都继承AQS,其中维护了一个status来记录重入次数。

优点

优点:一定程度降低死锁的情况

锁的范围(对象实例和类对象)

普通方法上加上synchronized锁住的是单独对象的这个方法

静态方法(static)加上synchronized锁住的是所有对象的这个方法