Java中的公平锁和非公平锁

1、什么是公平锁和非公平锁

公平锁和非公平锁是指在多线程环境下,如何对锁进行获取的顺序和策略的不同。

公平锁是指多个线程按照申请锁的顺序来获取锁,即先到先得的策略。当一个线程释放锁之后,等待时间最长的线程将获得锁。公平锁的优点是保证了每个线程的公平性,不存在饥饿现象,但是由于需要维护一个等待队列,因此会增加系统的开销。

非公平锁是指多个线程获取锁的顺序是不确定的,不一定按照申请锁的顺序来获取锁。当一个线程释放锁之后,锁的获取是由系统的调度算法来决定的。非公平锁的优点是可以减少线程上下文切换的开销,提高系统的吞吐量,但是容易出现饥饿现象,即某些线程可能会一直获取不到锁。

一般来说,公平锁适用于对线程公平性要求比较高的场景,而非公平锁适用于对性能要求比较高的场景。但是在具体应用时,需要根据实际情况来选择合适的锁。

● 公平锁:是指多个线程按照申请的顺序来获取值。在并发环境中,每一个线程在获取锁时会先查看此锁维护的等待队列,如果为空,或者当前线程是等待队列的第一个就占有锁,否者就会加入到等待队列中,以后会按照 FIFO 的规则获取锁

● 非公平锁:是指多个线程获取值的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁。在并发环境中一上来就尝试占有锁,如果失败再进行排队,可能会造成优先级翻转或者饥饿现象

    // 常用的ReentrantLock无参构造默认是非公平锁/**
     * Creates an instance of {@code ReentrantLock}.
     * This is equivalent to using {@code ReentrantLock(false)}.
     */public ReentrantLock() {
        sync = new NonfairSync();}/**
     * Creates an instance of {@code ReentrantLock} with the
     * given fairness policy.
     *
     * @param fair {@code true} if this lock should use a fair ordering policy
     */public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();}

2、Java中的公平锁和非公平锁

Java中的公平锁和非公平锁主要有以下几种:

ReentrantLock的公平锁和非公平锁:ReentrantLock是Java中常用的锁实现类之一,它提供了公平锁和非公平锁两种模式。在创建ReentrantLock对象时,可以通过构造函数传入一个布尔类型的fair参数来指定锁的模式。如果fair为true,则创建公平锁;如果fair为false,则创建非公平锁。

ReentrantReadWriteLock的公平锁和非公平锁:ReentrantReadWriteLock是一个读写锁,它也提供了公平锁和非公平锁两种模式。在创建ReentrantReadWriteLock对象时,可以通过构造函数传入一个布尔类型的fair参数来指定锁的模式。如果fair为true,则创建公平锁;如果fair为false,则创建非公平锁。

StampedLock的乐观锁和悲观锁:StampedLock是Java 8中新增的一种锁实现类,它提供了乐观锁和悲观锁两种模式。在使用StampedLock时,可以通过调用tryOptimisticRead()方法来获取乐观锁,或者通过调用readLock()方法来获取悲观锁。乐观锁是一种无锁的机制,它不会阻塞线程,但是需要通过validate()方法来检查锁是否仍然有效。

Synchronized的非公平锁:Synchronized是Java中内置的锁机制,它默认采用非公平锁模式。在使用Synchronized时,如果多个线程同时请求锁,则会根据系统的调度算法来决定哪个线程获取锁。

公平锁和非公平锁的性能和效率都会受到多种因素的影响,如锁的争用情况、线程的数量、系统的负载等。在实际应用中,需要根据具体情况选择合适的锁模式。

3、为什么Synchronized是非公平锁

Synchronized是Java中内置的锁机制,它的锁模式是非公平锁,这是因为Synchronized的实现方式是基于对象监视器(monitor)的。

在Java中,每个对象都有一个与之关联的monitor,当一个线程需要获取某个对象的锁时,它会首先尝试获取这个对象关联的monitor。如果monitor已经被其他线程占用,那么这个线程就会进入monitor的等待队列中,等待其他线程释放锁。

在Synchronized中,当一个线程释放锁时,JVM会从等待队列中随机选择一个线程来获取锁,而不是按照申请锁的顺序来获取锁,因此Synchronized是一种非公平锁。这种实现方式的优点是可以减少线程上下文切换的开销,提高系统的吞吐量,但是容易出现饥饿现象,即某些线程可能会一直获取不到锁。

Synchronized也可以通过在代码中使用wait()和notify()方法来实现公平锁,但是这种方式比较复杂,容易出错,而且性能也不如ReentrantLock的公平锁实现方式。因此,在实际应用中,如果需要公平锁,建议使用ReentrantLock。

4、Synchronized代码示例

下面是一个简单的Synchronized使用示例:

4.1、修饰方式

public class SynchronizedExample {private int count = 0;public synchronized void increment() {
        count++;}public static void main(String[] args) throws InterruptedException {SynchronizedExample example = new SynchronizedExample();Thread thread1 = new Thread(() -> {for (int i = 0; i < 10000; i++) {
                example.increment();}});Thread thread2 = new Thread(() -> {for (int i = 0; i < 10000; i++) {
                example.increment();}});        thread1.start();
        thread2.start();        thread1.join();
        thread2.join();System.out.println("Count: " + example.count);}
}

输入结果如下:

在这个示例中,Synchronized被用于修饰increment()方法,这样在同一时刻只有一个线程可以执行该方法。这个示例中创建了两个线程,分别对count变量进行自增操作。由于Synchronized的作用,这些操作是互斥的,所以最终输出的count值应该是20000。

4.2、修饰代码块

除了修饰方法,Synchronized还可以修饰代码块。下面是一个使用Synchronized修饰代码块的示例:

public class SynchronizedExample {private int count = 0;private final Object lock = new Object();public void increment() {synchronized (lock) {
            count++;}}public static void main(String[] args) throws InterruptedException {SynchronizedExample example = new SynchronizedExample();Thread thread1 = new Thread(() -> {for (int i = 0; i < 10000; i++) {
                example.increment();}});Thread thread2 = new Thread(() -> {for (int i = 0; i < 10000; i++) {
                example.increment();}});        thread1.start();
        thread2.start();        thread1.join();
        thread2.join();System.out.println("Count: " + example.count);}
}

在这个示例中,Synchronized被用于修饰代码块,这样在同一时刻只有一个线程可以执行该代码块。在这个示例中,lock对象被用于作为Synchronized锁的对象。

5、总结

需要注意的是,Synchronized锁的是对象,而不是代码。在同一个对象上使用Synchronized修饰的代码块或方法是互斥的,但不同对象上的Synchronized代码块或方法并不互斥。

Synchronized虽然可以保证线程安全,但是它会导致性能问题。在使用Synchronized时需要注意以下几点:

尽量缩小Synchronized的作用范围,只在必要的代码块或方法上使用Synchronized。

尽量不要在Synchronized代码块或方法中调用其他耗时的方法,这会导致其他线程长时间等待。

尽量使用Lock接口代替Synchronized,因为Lock接口提供了更灵活的锁定机制。

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

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

相关文章

java 中钻石操作符 <> 的使用场景

在 Java 中,<> 符号通常被称为 "钻石操作符" (Diamond Operator),主要用于泛型类型的简化表示。<> 操作符引入于 Java 7,以减少泛型实例化时的冗余代码。以下是 <> 符号在 Java 中的几种主要使用场景: 1. 泛型类型实例化 在 Java 7 之前,实…

Redis主从部署

文章目录 Redis主从部署1.下载安装Redis2.单点双副本主从配置1.修改配置信息2.修改配置文件redis.conf3.拷贝配置文件到每一个实例文件夹里4.修改每一个实例的端口和工作目录5.配置主从关系6.检查效果 3.哨兵模式监控主从1.创建实例目录2.复制配置文件并进行修改3.启动并测试 4…

微信定时推送LeetCode每日一题,再也不怕没人喊你刷题了

前段时间发过一篇关于微信机器人开发的文章&#xff0c;讲述了如何快速开发一个微信机器人&#xff0c;本篇文章就来实现一个最近开发的一个功能案例&#xff0c;在这个案例中会遇到了各种问题&#xff0c;可以帮助大家减少自己去踩坑的时间。通过此案例也可以帮助你去扩想一些…

Profibus_DP转ModbusTCP网关模块连马保与上位机通讯

Profibus转ModbusTCP网关模块&#xff08;XD-ETHPB20&#xff09;广泛应用于工业自动化领域。例如&#xff0c;可以将Profibus网络中的传感器数据转换为ModbusTCP协议&#xff0c;实现数据的实时监控和远程控制。本文介绍了如何利用Profibus转ModbusTCP网关&#xff08;XD-ETHP…

leetcode134双周赛 子数组按位与值为 K 的数目「动态规划」「位运算」

3209. 子数组按位与值为 K 的数目 题目描述 给你一个整数数组 nums 和一个整数 k &#xff0c;请你返回 nums 中有多少个子数组满足&#xff1a;子数组中所有元素按位 AND 的结果为 k 思路1:动态规划 打力扣打PTSD了&#xff0c;看什么题都是DP 状态&#xff1a; d p [ i …

c++ 宏和模板

&#xff08;1&#xff09;宏的应用 宏定义可以实现类似于函数的功能&#xff0c;但是它终归不是函数&#xff0c;而宏定义中括弧中的“参数”也不是真的参数&#xff0c;在宏展开的时候对 “参数” 进行的是一对一的替换。 assert() 断言 断言&#xff0c;是宏&#xff0c;…

【AMBA】AHB总线中的HTRANS、HSIZE、HBURST以及1K边界问题

HTRANS、HSIZE和HBURST共同决定下一次数据传输的地址。 HTRANS[1:0]定义传输类型 HTRANS[1:0]主机传输状态描述00IDLE空闲表示没有进行数据传输&#xff0c;默认状态。主设备虽然可能已经占用了总线&#xff0c;但是还没有开始传输数据。从设备需要返回OKAY响应01BUSY忙主设备…

springboot+vue项目实战2024第二集jwt

1.登陆注册校验token,jwt校验 <!--java-jwt--><dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>4.4.0</version></dependency> <!--test--><dependency><groupId&…

在 Node.js 中,如何正确地使用 async/await 与 Promise 对象配合

在 Node.js 中&#xff0c;如何正确地使用 async/await 与 Promise 对象配合? 在Node.js中&#xff0c;async/await是ES2017引入的一种更简洁的处理异步操作的方式&#xff0c;它基于Promise来进行编写&#xff0c;使得异步代码看起来更像同步代码&#xff0c;易于理解和维护…

重塑视听盛宴:揭秘短剧系统开发背后的创意引擎与技术革新!

重塑视听盛宴&#xff0c;短剧系统的开发背后融合了强大的创意引擎与技术革新。这些创新不仅提升了观众的观剧体验&#xff0c;还极大地丰富了内容创作和分发的方式。 创意引擎 内容创新 1、多元化内容资源&#xff1a;短剧系统汇聚了全球各地的优质短剧资源&#xff0c;涵盖悬…

前端面试39(关于git)

针对前端开发者的Git面试题可以覆盖Git的基础概念、常用命令、工作流程、团队协作、以及解决冲突等方面。以下是一些具体的Git面试 Git基础知识 什么是Git&#xff1f; Git是一个分布式版本控制系统&#xff0c;用于跟踪计算机文件的更改&#xff0c;并协调多个人共同在一个项…

基于视觉的具身导航

基于视觉的具身导航 背景 什么是&#xff08;视觉的&#xff1f;&#xff09;具身导航 输入机器人观测的当前图像 o t o_t ot​和目标图像 o G o_G oG​&#xff0c;输出当前时间步的控制动作 u t u_t ut​&#xff0c;最终到达指定地点的算法流程。 通用的评价指标 性能指…

Git常见命令和用法

Git 文件状态 Git 文件 2 种状态: 未跟踪:新文件&#xff0c;从未被 Git 管理过已跟踪:Git 已经知道和管理的文件 常用命令 命令作用注意git -v查看 git 版本git init初始化 git 仓库初始化之后有工作区、暂存区(本地库)、版本库git add 文件标识暂存某个文件文件标识以终…

人工智能建立在对象存储上的真正原因

tl;dr: 在这篇文章中&#xff0c;我们将探讨 AI 工作负载依赖高性能对象存储的四个技术原因。 1. 对非结构化数据没有限制 在当前的机器学习范式中&#xff0c;性能和能力与计算成比例&#xff0c;计算实际上是数据集大小和模型大小的代理&#xff08;神经语言模型的缩放定律&a…

C#开发:下载node.js指定版本

一、打开官网 二、找到指定版本 三、选择程序包msi下载 四、验证下载是否成功 cmd输入&#xff1a; node -v npm -v

请跳至打印机属性的“Adobe PDF设置”页面,取消选择“仅停靠系统字体;不使用文档字体”

场景&#xff1a; 当使用adobe pdf打印时&#xff0c;出现如下提示“请跳至打印机属性的“Adobe PDF设置”页面&#xff0c;取消选择“仅停靠系统字体&#xff1b;不使用文档字体””&#xff0c;该如何解决。 描述 □“仅停靠系统字体&#xff1b;不使用文档字体” 复选本框…

【GameFramework扩展应用】6-1、接入热更新框架HybridCLR

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址QQ群:398291828大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。 一、前言 【GameFramework框架】系列教程目录: https://blog.csdn.net/q764424567/article/details/1…

基坑安全:自动化监测系统的革新力量

在日新月异的基坑工程领域&#xff0c;基坑安全自动化监测系统犹如一位守护者&#xff0c;以其独特的优势&#xff0c;为工程的安全与质量保驾护航。该系统集先进的测量仪器、计算机技术与现代传感技术于一体&#xff0c;对基坑的围护结构及周边环境进行全方位、高精度的实时监…

从零开始学量化~Ptrade使用教程(四)——股票普通买卖与回购业务

股票普通买卖 股票买入 通过选择委托方向实现股票的买入与卖出&#xff0c;可根据输入的价格自动查询可买数量。 用鼠标点击【买入】&#xff0c;如图所示&#xff1a; 输入股票代码并选中后&#xff0c;选择委托类型&#xff0c;若为限价类型&#xff0c;输入委托价格&#xf…

【漏洞复现】锐捷校园网自助服务系统 任意文件读取

声明&#xff1a;本文档或演示材料仅用于教育和教学目的。如果任何个人或组织利用本文档中的信息进行非法活动&#xff0c;将与本文档的作者或发布者无关。 一、漏洞描述 锐捷校园网自助服务系统是用于学校网络管理的一个平台&#xff0c;login_judge.jsf接口存在任意文件读取…