java并发编程 ReentrantLock详解

文章目录

    • [1 概要](#1 概要)
    • [2 相关文章](#2 相关文章)
    • [3 例子](#3 例子)
    • [4 方法详解](#4 方法详解)
      • [4.1 lock()](#4.1 lock())
      • [4.2 unlock()](#4.2 unlock())
      • [4.3 tryLock()](#4.3 tryLock())
      • [4.4 其他](#4.4 其他)
      • 公平锁
    • 总结

1 概要

ReentrantLock 通过实现Lock接口的行为,提供锁机制。但是实现委托给了内部的Sync,Sync extends AbstractQueuedSynchronizer,继承了AQS的能力。此时还提供两个具体的实现,公平锁和非公平锁。首先如果对AQS不了解,请看java并发编程 AbstractQueuedSynchronizer(AQS)详解一。下文会对上述几个点进行详解内部原理

2 相关文章

  1. java并发编程 AbstractQueuedSynchronizer(AQS)详解一
  2. java并发编程 AbstractQueuedSynchronizer(AQS)详解二

3 例子

ReentrantLock 注释上的例子。。。。

如果lock没有被阻塞住就代表获取到锁,然后执行业务逻辑。最终finally 里释放锁,防止抛异常

java 复制代码
public class X {
    private final ReentrantLock lock = new ReentrantLock();    // ...     
    public void m() {      
        lock.lock();
    // block until condition holds      
        try {        
    // ... method body     
        } finally {        
            lock.unlock()  ;    
        }    
    }  
}

4 方法详解

先看非公平锁实现。

先说下在ReentrantLock里上锁是通过state变量,如果是0,且从0原子变成1成功代表获取成功,如果重入则state + 1,释放锁就减1,0的时候释放锁。

4.1 lock()

java 复制代码
public void lock() {
	//委托给sync执行
    sync.lock();
}
//非公平锁实现
final void lock() {
	//先自己尝试设置成1 如果成功设置拥有锁的线程为自己
 	if (compareAndSetState(0, 1))
        setExclusiveOwnerThread(Thread.currentThread());
    else
    	//aqs 的acquire 若对aqs不熟悉的,请先看相关文章
    	//他会进入tryAcquire(arg)的具体实现
        acquire(1);
}
protected final boolean tryAcquire(int acquires) {
    return nonfairTryAcquire(acquires);
}
//非公平的尝试加锁
final boolean nonfairTryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
    	//如果是0 尝试变成1,此时如果阻塞队列中有阻塞的线程,但是新的加锁线程还是有可能获取到锁的,
    	//因为释放锁后只会从Head.next的Node去唤醒获取锁, 你后来的线程比先来的先拿到锁,公平吗? 非公平锁
        if (compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    //可重入的实现。如果当前线程是自己,也就是lock拿到锁再lock直接state + 1, 因为独占锁,所以不需要原子性+1
    else if (current == getExclusiveOwnerThread()) {
        int nextc = c + acquires;
        if (nextc < 0) // overflow
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    //现在state不是0且持有锁的线程不是自己,尝试加锁失败
    return false;
}

4.2 unlock()

持有锁的线程释放锁

java 复制代码
public void unlock() {
    sync.release(1);
}

public final boolean release(int arg) {
	// aqs的抽象实现
    if (tryRelease(arg)) {
    	//成功了会唤醒head.next线程
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    //释放失败 可重入的时候从5 -> 4
    return false;
}
protected final boolean tryRelease(int releases) {
	//不需要原子性操作是因为当前持有锁
    int c = getState() - releases;
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    //state = 0 的时候代表释放锁
    if (c == 0) {
        free = true;
        setExclusiveOwnerThread(null);
    }
    setState(c);
    return free;
}

4.3 tryLock()

对比lock 其实就没有进入阻塞队列的逻辑。比较简单

java 复制代码
public boolean tryLock() {
    return sync.nonfairTryAcquire(1);
}

4.4 其他

其他方法都可类比lock 和 unlock。如阻塞一段时间的等。

公平锁

公平锁核心方法实现,对比下和非公平锁的区别就可以看到,多了!hasQueuedPredecessors()

这个方法。很清晰。

java 复制代码
protected final boolean tryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
    	//区别在这,如果阻塞队列有阻塞的线程,就不去争抢,会return false
        if (!hasQueuedPredecessors() &&
            compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    else if (current == getExclusiveOwnerThread()) {
        int nextc = c + acquires;
        if (nextc < 0)
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    return false;
}
//阻塞队列中没有阻塞的线程
public final boolean hasQueuedPredecessors() {
    Node t = tail;
    Node h = head;
    Node s;
    return h != t &&
        ((s = h.next) == null || s.thread != Thread.currentThread());
}

总结

ReentrantLock 本质上是基于AQS实现的可重入锁,且提供了公平和非公平的机制,逻辑较为简单,需要对AQS熟练掌握。

相关推荐
V+zmm1013410 分钟前
基于微信小程序的乡村政务服务系统springboot+论文源码调试讲解
java·微信小程序·小程序·毕业设计·ssm
Oneforlove_twoforjob35 分钟前
【Java基础面试题025】什么是Java的Integer缓存池?
java·开发语言·缓存
xmh-sxh-131437 分钟前
常用的缓存技术都有哪些
java
AiFlutter1 小时前
Flutter-底部分享弹窗(showModalBottomSheet)
java·前端·flutter
J不A秃V头A2 小时前
IntelliJ IDEA中设置激活的profile
java·intellij-idea
DARLING Zero two♡2 小时前
【优选算法】Pointer-Slice:双指针的算法切片(下)
java·数据结构·c++·算法·leetcode
小池先生2 小时前
springboot启动不了 因一个spring-boot-starter-web底下的tomcat-embed-core依赖丢失
java·spring boot·后端
CodeClimb2 小时前
【华为OD-E卷-木板 100分(python、java、c++、js、c)】
java·javascript·c++·python·华为od
程序员厉飞雨2 小时前
Android R8 耗时优化
android·java·前端
odng2 小时前
IDEA自己常用的几个快捷方式(自己的习惯)
java·ide·intellij-idea