图解Java ReentrantLock公平锁和非公平锁的实现

yizhihongxing

图解Java ReentrantLock公平锁和非公平锁的实现攻略

什么是ReentrantLock

ReentrantLock是一个可重入锁,也称为互斥锁,它比Java原生的synchronized更加灵活,支持公平锁和非公平锁,并且可以通过tryLock方法尝试获取锁,给予更好的控制和扩展。

公平锁和非公平锁

公平锁和非公平锁都是指ReentrantLock的获取锁机制。公平锁是按照请求锁的顺序排队,先请求锁的先获得锁,而非公平锁则不保证请求锁的顺序,也就是说后来的线程可能会在先前线程的前面请求到锁。

公平锁实现

公平锁的实现是基于FIFO队列的,通过一个带有head和tail指针的FIFO队列来维护请求锁的顺序,在每个节点都保存了前驱节点的信息,新的线程请求锁时,会将其加入到队列的末尾,且只有当前持有锁的线程释放锁的时候,才唤醒队列中的下一个线程。

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

private static final class FairSync extends Sync {
    // 公平锁使用FIFO队列
    final void lock() {
        acquire(1);
    }
    protected final boolean tryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        if (c == 0) { // 如果锁没有被占用
            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;
    }
}

非公平锁实现

与公平锁不同,非公平锁的实现没有排序的过程,它总是尝试获取锁,如果失败就进入等待状态,直到成功获取锁或者线程被中断或超时等不可抗力情况发生。

private static final class NonfairSync extends Sync {
    // 非公平锁使用CAS操作直接尝试获取锁
    final void lock() {
        if (compareAndSetState(0, 1))
            setExclusiveOwnerThread(Thread.currentThread());
        else
            acquire(1);
    }
    protected final boolean tryAcquire(int acquires) {
        return nonfairTryAcquire(acquires);
    }
}

示例

下面我们通过两个示例来说明公平锁和非公平锁的区别。

假设有两个线程A和B,并且有一个非公平锁lock。

示例1:使用公平锁

ReentrantLock fairLock = new ReentrantLock(true);
fairLock.lock();
System.out.println("A acquire fairLock");
fairLock.lock();
System.out.println("B acquire fairLock");
fairLock.unlock();
System.out.println("A release fairLock");
fairLock.unlock();
System.out.println("B release fairLock");

输出结果为:

A acquire fairLock
B acquire fairLock
A release fairLock
B release fairLock

公平锁保证线程请求锁的顺序,所以期望的输出结果就是先有A取得锁,再有B取得锁,最后A释放锁,B也随后释放锁。

示例2:使用非公平锁

ReentrantLock nonfairLock = new ReentrantLock();
nonfairLock.lock();
System.out.println("A acquire nonfairLock");
nonfairLock.lock();
System.out.println("B acquire nonfairLock");
nonfairLock.unlock();
System.out.println("A release nonfairLock");
nonfairLock.unlock();
System.out.println("B release nonfairLock");

输出结果为:

A acquire nonfairLock
B acquire nonfairLock
A release nonfairLock
B release nonfairLock

由于非公平锁没有按照请求锁的顺序进行排序,所以线程B也可以在A获得锁后立即尝试获取,成功获得锁,然后先释放锁,线程A再接着去释放锁。

结论

公平锁显然比非公平锁更加公正,能够避免饥饿现象,但是由于需要排序和维护队列,开销会更大,而非公平锁相对更加简单和高效,但是有可能会出现饥饿情况。所以选择哪一种锁取决于实际应用场景和需求。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:图解Java ReentrantLock公平锁和非公平锁的实现 - Python技术站

(0)
上一篇 2023年6月26日
下一篇 2023年6月26日

相关文章

  • 如何使用Laravel Eloquent来开发无限极分类

    如何使用Laravel Eloquent来开发无限极分类 前言 在实际的开发中,分类是一种非常重要的数据结构。而在大多数情况下,我们并不能预见到分类的层级数,这时候无限极分类就派上用场了。本文将详细讲解如何使用Laravel Eloquent来实现无限极分类。 第一步:设计数据表 无限极分类的数据表需要有父类ID字段,用于记录当前分类的父级分类ID编号。当父…

    other 2023年6月27日
    00
  • 深入理解JVM自动内存管理

    深入理解JVM自动内存管理攻略 1. JVM内存模型 JVM内存模型由以下几个部分组成: 程序计数器(Program Counter):用于指示当前线程执行的字节码指令的地址。 Java虚拟机栈(Java Virtual Machine Stack):每个线程在运行时都会创建一个栈,用于存储局部变量、方法参数、返回值等。栈帧包含了方法的运行时数据。 本地方法…

    other 2023年8月1日
    00
  • win7中格式化C盘的命令行是什么

    下面是在Windows 7中格式化C盘的完整攻略,步骤如下: 1.打开命令提示符窗口。 在Windows 7中,可以通过以下方法打开命令提示符窗口: 点击“开始”菜单,在搜索栏中输入“cmd”,然后按Enter键。 使用快捷键Win+R,输入“cmd”,然后按Enter键。 2.以管理员身份运行命令提示符。 在开始菜单中找到“命令提示符”,右键点击并选择“以…

    other 2023年6月26日
    00
  • sasblandaltman分析

    以下是关于“SAS Bland-Altman分析”的完整攻略,包括基本概念、步骤和两个示例。 基本概念 Bland-Altman分析是一种用于比较两种测量方法的方法,它可以评估两种方法之间的一致性偏差。在SAS中,可以使用 BlandAltman命令来执行Bland-Altman分析。 步骤 以下是使用SAS执行Bland-Altman分析的步骤: 准备数据…

    other 2023年5月7日
    00
  • C语言实现动态链表的示例代码

    让我们来讲解C语言实现动态链表的示例代码的完整攻略。 1. 概述 动态链表是指链表在运行时动态地申请内存空间,可以根据需要自由地进行插入和删除操作。相对于静态链表,动态链表具有更大的灵活性和扩展性。 在C语言中,动态链表可以通过结构体指针实现。本文介绍了一个简单的C语言实现动态链表的示例代码。 2. 定义链表结构体 首先,我们需要定义链表的结构体,包括数据和…

    other 2023年6月27日
    00
  • 详解Java中使用externds关键字继承类的用法

    详解Java中使用extends关键字继承类的用法 在Java中,我们可以使用extends关键字继承已有的类,这样子就可以在原有类的基础上进行扩展和功能添加。本文将详细讲解extends关键字的用法。 语法规则 在Java中,使用extends关键字继承类的语法规则如下: class SubClass extends SuperClass { // 一些其…

    other 2023年6月26日
    00
  • Java中StringBuilder与StringBuffer使用及源码解读

    Java中StringBuilder与StringBuffer使用及源码解读 StringBuilder与StringBuffer的概述 StringBuilder与StringBuffer是Java中两个非常常用的字符串拼接工具,在处理大量字符串拼接时,它们相比于String的”+”连接符表现更加出色。 这两个类都继承自AbstractStringBuil…

    other 2023年6月27日
    00
  • Windows 10预览版惊人发现 内藏完整Android子系统

    Windows 10预览版惊人发现 内藏完整Android子系统攻略 最近有消息称,微软在Windows 10预览版中内置了完整的Android子系统,这个消息让许多Windows和Android用户感到惊讶。本文将提供详细的攻略,让大家了解如何使用Windows 10预览版的Android子系统。 第一步:确保已经安装Windows 10预览版 首先,需要…

    other 2023年6月28日
    00
合作推广
合作推广
分享本页
返回顶部