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

图解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日

相关文章

  • 通俗易懂讲解C语言与Java中二叉树的三种非递归遍历方式

    通俗易懂讲解C语言与Java中二叉树的三种非递归遍历方式 本文将讲解C语言和Java中二叉树的三种非递归遍历方式:先序遍历、中序遍历和后序遍历。这三种遍历方式分别可以使用栈来实现非递归遍历。下面将详细讲解这三种遍历方式的实现过程。 先序遍历 先序遍历的遍历顺序是中->左->右。实现的过程如下: struct TreeNode { int val;…

    other 2023年6月27日
    00
  • Angular.js之作用域scope’@’,’=’,’&’实例详解

    Angular.js之作用域(scope) ‘@’, ‘=’, ‘&’ 实例详解 Angular.js是一个流行的JavaScript框架,它使用了一种称为作用域(scope)的概念来管理数据和事件。作用域(scope)是一个对象,它将控制器(controller)和视图(view)连接起来,使它们能够相互通信。 在Angular.js中,作用域(s…

    other 2023年8月19日
    00
  • Hadoop2.X/YARN环境搭建–CentOS7.0 JDK配置

    Hadoop2.X/YARN环境搭建–CentOS7.0 JDK配置 环境准备 系统:CentOS 7.0 JDK版本:Java 1.8 JDK配置 下载JDK:在官网下载JDK安装包,或者使用yum命令安装: sudo yum install java-1.8.0-openjdk-devel 配置环境变量:在/etc/profile文件中添加以下内容: …

    other 2023年6月27日
    00
  • ppt中怎么绘制一个烟花绽放的动画?

    绘制一个烟花绽放的动画可以利用PPT中的动画效果来实现。具体步骤如下: 步骤1:绘制烟花模型 首先,使用PPT中的形状工具绘制一个圆形作为烟花的主体,然后在其上方插入多个不同大小和角度的三角形作为烟花的花瓣。 示例1: 1. 点击插入 ->形状->圆形,选中圆形形状 2. 在圆形形状上方选中三角形形状,按住Ctrl键,复制(拖放)不同大小和角度的…

    other 2023年6月27日
    00
  • iOS自定义日期选择器

    iOS自定义日期选择器是指开发者可以在iOS应用程序中使用自行编写的日期选择器而非使用系统提供的UIDatePicker。 下面是关于自定义日期选择器的完整攻略: 一、设计思路 1.确定选择器的外观和交互方式2.实现日期选择器的布局3.实现日期选择器的逻辑功能 二、外观和交互方式 在设计日期选择器的外观和交互方式时,需要考虑用户体验和应用程序的主题。 可以选…

    other 2023年6月26日
    00
  • 使用latex插入数学公式(二)

    使用LaTeX插入数学公式(二) 在上一篇文章中,我们介绍了如何使用LaTeX插入数学公式,包括行内公式和行间公式的使用方法。然而,有一些特殊的数学公式需要我们掌握一些额外的知识才能够正确地插入。本文将进一步介绍如何在LaTeX中插入分数、根号、希腊字母等特殊符号,以及如何对多行公式进行对齐。 插入分数 插入分数可以使用\frac{分子}{分母}的命令,其中…

    其他 2023年3月29日
    00
  • win11系统正式版怎么下载 win11正式版下载地址分享

    Win11系统正式版下载攻略 Win11系统正式版已经发布,以下是下载Win11系统正式版的详细攻略。 步骤一:检查系统要求 在下载Win11系统正式版之前,首先要确保你的计算机符合以下最低系统要求: 处理器:64位处理器,至少为1 GHz的时钟速度,双核心以上 内存:至少4 GB RAM 存储空间:至少64 GB的存储空间 显卡:兼容DirectX 12或…

    other 2023年8月3日
    00
  • Pycharm如何自动生成头文件注释

    PyCharm 自动添加头文件注释可以通过以下几个步骤完成: 打开 PyCharm。点击顶部菜单栏的 “Code” 选项,选择 “Insert File Header…”,进入编辑器。 在弹出的编辑框中,输入头文件注释的模板。可以设置该文件的创建人、创建时间、作者等信息。如下所示: #!/usr/bin/env python # -*- coding: …

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