Java那些“锁”事 - 公平锁和非公平锁

news2024/11/24 15:51:39

在Java中,锁可以分为公平锁(Fair Lock)和非公平锁(Nonfair Lock),它们的区别在于线程获取锁的顺序是否遵循公平性原则。

 

公平锁

        公平锁是指多个线程按照它们发出请求的顺序获取锁,即先到先得的原则。当一个线程释放锁时,等待时间最长的线程将有更大的机会获取到锁。公平锁的优点是保证了资源的公平分配,并且避免饥饿现象。但是,由于需要维护一个等待队列,因此公平锁的性能通常相对较低。

非公平锁

        非公平锁是指多个线程获取锁的顺序没有明确的规定,线程获取锁的机会是随机分配的。即使有新的线程等待获取锁时,当前持有锁的线程有可能再次获取到锁。非公平锁的优点是相对较高的吞吐量,因为它省去了维护等待队列的开销。但是,非公平锁可能会导致一些线程长时间地等待,从而产生“插队”现象,不遵循公平性原则。

ReentrantLock非公平案例

        有一个资源类(Ticket ),包含一个number变量表示50张票,还有一个lock变量保证“票”资源被售票员有序的售出。

/**
 * 资源类
 */
class Ticket {

    private Integer number = 30;
    private ReentrantLock lock = new ReentrantLock();

    public void sale() {
        lock.lock();
        try {
            if (number > 0) {
                System.out.println(Thread.currentThread().getName() + "卖出第 " + (number--) + " 张票,还剩下:" + number);
            }
        } finally {
            lock.unlock();
        }
    }
}

        三个售票员卖完30张票:

 public static void main(String[] args) {

        Ticket ticket = new Ticket();

        //模拟三个售票员卖完50张票
        new Thread(() -> {
            for (int i = 0; i < 31; i++) {
                ticket.sale();
            }
        }, "售票员A").start();

        new Thread(() -> {
            for (int i = 0; i < 31; i++) {
                ticket.sale();
            }
        }, "售票员B").start();

        new Thread(() -> {
            for (int i = 0; i < 31; i++) {
                ticket.sale();
            }
        }, "售票员C").start();
    }

        结果打印:

售票员A卖出第 30 张票,还剩下:29
售票员A卖出第 29 张票,还剩下:28
售票员A卖出第 28 张票,还剩下:27
售票员A卖出第 27 张票,还剩下:26
售票员A卖出第 26 张票,还剩下:25
售票员A卖出第 25 张票,还剩下:24
售票员A卖出第 24 张票,还剩下:23
售票员C卖出第 23 张票,还剩下:22
售票员C卖出第 22 张票,还剩下:21
售票员C卖出第 21 张票,还剩下:20
售票员C卖出第 20 张票,还剩下:19
售票员C卖出第 19 张票,还剩下:18
售票员C卖出第 18 张票,还剩下:17
售票员C卖出第 17 张票,还剩下:16
售票员C卖出第 16 张票,还剩下:15
售票员C卖出第 15 张票,还剩下:14
售票员C卖出第 14 张票,还剩下:13
售票员C卖出第 13 张票,还剩下:12
售票员C卖出第 12 张票,还剩下:11
售票员C卖出第 11 张票,还剩下:10
售票员C卖出第 10 张票,还剩下:9
售票员C卖出第 9 张票,还剩下:8
售票员C卖出第 8 张票,还剩下:7
售票员C卖出第 7 张票,还剩下:6
售票员C卖出第 6 张票,还剩下:5
售票员C卖出第 5 张票,还剩下:4
售票员C卖出第 4 张票,还剩下:3
售票员C卖出第 3 张票,还剩下:2
售票员C卖出第 2 张票,还剩下:1
售票员C卖出第 1 张票,还剩下:0

        可以看到前面7张票是售票员A卖出去的,但是后面的27张票都是售票员C卖出去的。原因是我们在资源类中的ReentrantLock使用其默认的构造方法new出来的锁对象,ReentrantLock默认是非公平锁:

     //ReentrantLock构造方法创建的是非公平锁
     public ReentrantLock() {
        sync = new NonfairSync();
    }

ReentrantLock公平案例

       我们把资源类(Ticket)中的lock对象设置成公平锁。

/**
 * 资源类
 */
class Ticket {

    private Integer number = 30;
    private ReentrantLock lock = new ReentrantLock(true);

    public void sale() {
        lock.lock();
        try {
            if (number > 0) {
                System.out.println(Thread.currentThread().getName() + "卖出第 " + (number--) + " 张票,还剩下:" + number);
            }
        } finally {
            lock.unlock();
        }
    }
}

        三个售票员卖完30张票:

   public static void main(String[] args) {

        Ticket ticket = new Ticket();

        //模拟三个售票员卖完50张票
        new Thread(() -> {
            for (int i = 0; i < 31; i++) {
                ticket.sale();
            }
        }, "售票员A").start();

        new Thread(() -> {
            for (int i = 0; i < 31; i++) {
                ticket.sale();
            }
        }, "售票员B").start();

        new Thread(() -> {
            for (int i = 0; i < 31; i++) {
                ticket.sale();
            }
        }, "售票员C").start();
    }

        结果打印:

售票员A卖出第 30 张票,还剩下:29
售票员A卖出第 29 张票,还剩下:28
售票员A卖出第 28 张票,还剩下:27
售票员B卖出第 27 张票,还剩下:26
售票员A卖出第 26 张票,还剩下:25
售票员C卖出第 25 张票,还剩下:24
售票员B卖出第 24 张票,还剩下:23
售票员A卖出第 23 张票,还剩下:22
售票员C卖出第 22 张票,还剩下:21
售票员B卖出第 21 张票,还剩下:20
售票员A卖出第 20 张票,还剩下:19
售票员C卖出第 19 张票,还剩下:18
售票员B卖出第 18 张票,还剩下:17
售票员A卖出第 17 张票,还剩下:16
售票员C卖出第 16 张票,还剩下:15
售票员B卖出第 15 张票,还剩下:14
售票员A卖出第 14 张票,还剩下:13
售票员C卖出第 13 张票,还剩下:12
售票员B卖出第 12 张票,还剩下:11
售票员A卖出第 11 张票,还剩下:10
售票员C卖出第 10 张票,还剩下:9
售票员B卖出第 9 张票,还剩下:8
售票员A卖出第 8 张票,还剩下:7
售票员C卖出第 7 张票,还剩下:6
售票员B卖出第 6 张票,还剩下:5
售票员A卖出第 5 张票,还剩下:4
售票员C卖出第 4 张票,还剩下:3
售票员B卖出第 3 张票,还剩下:2
售票员A卖出第 2 张票,还剩下:1
售票员C卖出第 1 张票,还剩下:0

        可以看到30张票的出售情况,后面都是售票员A、售票员B、售票C个出售一张的情况。我们创建ReentrantLock实例通过指定构造方法中传入true创建了一个公平锁对象。

    //通过传入参数(false/ture)可以指定是公平锁还是非公平锁
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

选择使用公平锁还是非公平锁取决于具体的场景和需求。如果对线程之间的公平性要求比较高,或者需要避免饥饿现象,可以选择公平锁。如果对吞吐量更关注,并且能够容忍某些线程“插队”,可以选择非公平锁。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/795034.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

QT:当登录成功时,关闭登录界面,跳转到新的界面中

1> 继续完善登录框&#xff0c;当登录成功时&#xff0c;关闭登录界面&#xff0c;跳转到新的界面中 widget.h #include "widget.h" //#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent)//, ui(new Ui::Widget) {//ui->setu…

Cesium态势标绘专题-集结地(标绘+编辑)

标绘专题介绍:态势标绘专题介绍_总要学点什么的博客-CSDN博客 入口文件:Cesium态势标绘专题-入口_总要学点什么的博客-CSDN博客 辅助文件:Cesium态势标绘专题-辅助文件_总要学点什么的博客-CSDN博客 本专题没有废话,只有代码,代码中涉及到的引入文件方法,从上面三个链…

IOS自动化测试环境搭建教程

目录 一、前言 二、环境依赖 1、环境依赖项 2、环境需求与支持 三、环境配置 1、xcode安装 2、Git安装 3、Homebrew安装&#xff08;用brew来安装依赖&#xff09; 4、npm和nodejs安装 5、libimobiledevice安装 6、idevicesinstaller安装 7、ios-deploy安装 8、Ca…

DRS 迁移本地mysql 到华为云

准备工作&#xff1a; 源端的IP地址&#xff08;公网&#xff09;&#xff0c;用户明和密码。如果通过公网迁移&#xff0c;需要在安全组放通drs访问源端数据库的3306端口。目标端的IP地址&#xff0c;用户名和密码。 创建DRS迁移任务 创建迁移任务 登录华为云控制台。单击管…

自恢复保险丝(PPTC)的金属材料说明

保险丝大家都是知道的&#xff0c;但保险丝当中的自恢复保险丝&#xff08;PPTC&#xff09;可能就不太了解的。 其实PPTC自恢复保险丝与大家所认识的保险丝一样&#xff0c;都是起到限流作用&#xff0c;达到电路防护效果。简单来说就是一旦电路中的电流超过所规定的电流时&am…

MixFormerV2: Efficient Fully Transformer Tracking

摘要 基于变压器的跟踪器在标准基准测试上取得了很强的精度。然而&#xff0c;它们的效率仍然是在GPU和CPU平台上实际部署的一个障碍。在本文中&#xff0c;为了克服这一问题&#xff0c;我们提出了一个完全变压器跟踪框架&#xff0c;称为MixFormerV2&#xff0c;没有任何密集…

SpringBoot 配置⽂件

1.配置文件作用 整个项⽬中所有重要的数据都是在配置⽂件中配置的&#xff0c;⽐如&#xff1a; 数据库的连接信息&#xff08;包含⽤户名和密码的设置&#xff09;&#xff1b;项⽬的启动端⼝&#xff1b;第三⽅系统的调⽤秘钥等信息&#xff1b;⽤于发现和定位问题的普通⽇…

mac 安装 php 与 hyperf 框架依赖的扩展并启动 gptlink 项目

m系列 mac 安装 php 与 hyperf 框架依赖的扩展并启动 gptlink 项目 gptlink 项目是一个前后端一体化的 chatgpt 开源项目 gptlink 项目地址&#xff1a;https://github.com/gptlink/gptlink 安装 php 8.0 版本&#xff1a; brew install php8.0安装完成后提示如下&#xff…

面向对象之_多态_1

目录 一. 多态 多态是什么 二. 多态的构成条件 1. 虚函数 2. 虚函数重写&#xff08;隐藏&#xff09; 3. 父类型的引用或者指针调用 4. 多态的特殊情况 1) 子类可以不加 virtual 关键字 2) 协变 三. 关键字 1. virtual 2. final 3. override 四. 多态的原理 1. 虚…

【MST+离线】CF1851 G

Problem - G - Codeforces 题意&#xff1a; Code&#xff1a; #include <bits/stdc.h>#define int long longusing namespace std;const int N2e510; const int mod1e97;int a[N]; struct node {int x, y, val;bool operator < (const node &k) const {return …

疾风计划-程序设计基础-期末考试-05

擀面皮 有一块1x1的方形面团&#xff08;不考虑面团的厚度&#xff09;&#xff0c;其口感值为0。擀面师傅要将其擀成一个N x M&#xff08;纵向长N&#xff0c;横向宽M&#xff09;的面皮。师傅的擀面手法娴熟&#xff0c;每次下手&#xff0c;要么横向擀一下&#xff08;使得…

Ubuntu 20.04下的录屏与视频剪辑软件

ubuntu20.04下的录屏与视频剪辑 一、录屏软件SimpleScreenRecorder安装与使用 1、安装 2、设置录制窗口参数 3、开始录制 二、视频剪辑软件kdenlive的安装 1、安装 2、启动 一、录屏软件SimpleScreenRecorder安装与使用 1、安装 &#xff08;1&#xff09;直接在终端输入以下命…

嵌入式系统中的GPIO控制:从理论到实践与高级应用

本文将探讨嵌入式系统中的GPIO(通用输入输出)控制,着重介绍GPIO的原理和基本用法。我们将使用一个实际的示例项目来演示如何通过编程配置和控制GPIO引脚。将基于ARM Cortex-M微控制器,并使用C语言进行编写。 GPIO是嵌入式系统中最常见且功能最强大的接口之一。它允许硬件工…

【JVM】详解对象的创建过程

文章目录 1、创建对像的几种方式1、new关键字2、反射3、clone4、反序列化 2、创建过程步骤 1、检查类是否已经被加载步骤 2、 为对象分配内存空间1、指针碰撞针对指针碰撞线程不安全&#xff0c;有两种方案&#xff1a; 2、空闲列表选择哪种分配方式 步骤3、将内存空间初始化为…

C语言中的数组(详解)

C语言中的数组&#xff08;详解&#xff09; 一、一维数组1.一维数组的创建2.数组的初始化3.一维数组的使用4.一维数组在内存中的存储二、二维数组1.二维数组的创建2.二维数组的初始化3.二维数组的使用4.二维数组在内存中的存储三、数组越界四、数组作为函数参数1.冒泡排序2.数…

MySQL基础扎实——MySQL中有那些不同的表格

表格类型 在MySQL中&#xff0c;常见的表格类型有以下几种&#xff1a; MyISAM&#xff1a;是MySQL默认的表格类型&#xff0c;具有较高的性能和较小的存储空间占用。但是&#xff0c;MyISAM不支持事务、崩溃恢复和数据行级锁定。 InnoDB&#xff1a;是MySQL提供的一个更强大…

理解基本的Android编程 (1/2)

1、Android概述 Android 是一个开源的&#xff0c;基于 Linux 的移动设备操作系统。 Android开发优势 开放源代码 众多开发者及强大的社区 不断增长的市场 国际化的App集成 低廉的开发成本 更高的成功几率 丰富的开发环境 Android应用程序 Android 应用程序一般使用…

EtherNet/IP转Modbus网关以连接AB PLC

本案例为西门子S7-1200 PLC通过捷米特Modbus转EtherNet/IP网关捷米特JM-EIP-RTU连接AB PLC的配置案例。 网关分别从ETHERNET/IP一侧和MODBUS一侧读写数据&#xff0c;存入各自的缓冲区&#xff0c;网关内部将缓冲区的数据进行交换&#xff0c;从而实现两边数据的传输。 网关做为…

VMware NSX Advanced Load Balancer (NSX ALB) 22.1.4 - 负载均衡平台

VMware NSX Advanced Load Balancer (NSX ALB) 22.1.4 - 负载均衡平台 请访问原文链接&#xff1a;https://sysin.org/blog/vmware-nsx-alb-22/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org 负载均衡平台 NSX Advanced Load…

SpringBoot-6

Spring Boot 中的 MVC 支持 Spring Boot 的 MVC 支持主要来最常用的几个注解&#xff0c;包括RestController 用于声明控制器、RequestMapping用于实现方法映射地址、PathVariable 用于接受路径中的参数、RequestParam 用于接受 request 请求中的参数以及RequestBody 用于接受…