<JavaEE> 锁进阶 -- 锁策略(乐观锁和悲观锁、重量级锁和轻量级锁、自旋锁和挂起等待锁、可重入锁和不可重入锁、公平锁和非公平锁、读写锁)

目录

一、锁策略介绍

二、乐观锁和悲观锁

三、轻量级锁和重量级锁

四、自旋锁和挂起等待锁

五、公平锁和非公平锁

六、可重入锁和不可重入锁

七、读写锁


一、锁策略介绍

        加锁的目的是为了保证线程安全,根据不同的实际情况,锁也会有不同的策略来应对。

以下将介绍多种锁策略,包括:

1)乐观锁 和 悲观锁
2)轻量级锁 和 重量级锁
3)自旋锁 和 挂起等待锁
4)读写锁
5)公平锁 和 非公平锁
6)可重入锁 和 不可重入锁

二、乐观锁和悲观锁

乐观锁在加锁之前进行预估,如果预估锁冲突发生概率不大或锁冲突不激烈,则不会在加锁时做太多工作,因此加锁速度也快,称为乐观锁。
悲观锁在加锁之前进行预估,如果预估锁冲突发生概率较大或锁冲突激烈,则需要在加锁时做更多工作,因此加锁速度也慢,称为悲观锁。
synchronized 是乐观锁还是悲观锁?
synchronized 在初始阶段是乐观锁,但如果发现锁竞争变得频繁,也会根据场景的变化而转换为悲观锁。

三、轻量级锁和重量级锁

图示演示锁的层次:

重量级锁重量级锁重度依赖mutex互斥锁,这种互斥锁是由CPU指令实现的,CPU指令又具有原子性。因此,使用重量级锁会引发大量的内核态和用户态切换,容易引发线程调度,加锁开销大。
轻量级锁轻量级锁则尽量不使用mutex互斥锁,代码能在用户态处理就尽量不切换内核态,除非确实需要时,才会使用mutex互斥锁,因此不容易发生用户态和内核态的切换,也不容易引发线程调度。
1)synchronized 是轻量级锁还是重量级锁?
synchronized 在初始阶段是轻量级锁,但如果发现锁竞争变得频繁,也会根据场景的变化而转换为重量级锁。
2)轻量级锁和重量级锁、乐观锁和悲观锁,这两中类型的锁之间有什么关系?

轻量级锁加锁开销小,加锁速度快,是乐观锁;

重量级锁枷锁开销大,加锁速度慢,是悲观锁;

由此可以看出,轻量级锁和重量级锁、乐观锁和悲观锁,其实是对同一个事物不同角度的描述。

锁的轻量与重量,是从加锁时做的工作的多少来判定的;

而锁的乐观与悲观,是从加锁前对后续工作量的预估来判定的。


四、自旋锁和挂起等待锁

自旋锁

如果获取锁失败,将会在极短的时间内再次尝试获取。获取锁这个行为会不断循环,直到成功获取到锁。

自旋锁没有放弃CPU,不涉及线程阻塞和调度,一旦锁被释放,就会第一时间获得锁。但与此同时,如果锁被其他线程长期持有,那么自旋锁就会持续占用CPU资源,造成资源浪费。

挂起等待锁

如果获取锁失败,会让线程挂起等待,直到锁释放或满足其他条件,再重新尝试获取锁。

挂起等待时,内核调度器会介入,此时线程被调度离开,此时CPU资源释放,可以另作其他用途,但重新获取锁的开销也就随之变大。

1)synchronized 是自旋锁还是挂起等待锁?
synchronized 在初始阶段是自旋锁,但如果发现锁竞争变得频繁,也会根据场景的变化而转换为挂起等待锁。
2)轻量级锁和重量级锁、乐观锁和悲观锁、自旋锁和挂起等待锁之间有什么关系?

自旋锁是轻量级锁的一种具体实现,同时也是一种乐观锁;

挂起等待锁则是重量级锁的一种具体实现,同时也是一种悲观锁。


五、公平锁和非公平锁

公平锁在线程阻塞后,形成一个等待队列,在待锁释放后,等待的线程按照“先来后到”的顺序获得锁。
非公平锁在锁释放之后,等待锁的线程一同竞争锁,不关心哪个线程先等待的。
1)synchronized 是公平锁还是非公平锁?

synchronized 是非公平锁。

操作系统内部的线程调度是无序的,synchronized 并没有使用额外的数据结构来记录线程的阻塞顺序,没有对随即调度这个机制进行限制,因此是非公平锁。

2)公平锁一定比非公平锁好吗?

公平锁天然就不会产生“线程饿死”问题。

但是,公平锁和非公平锁没有优劣之分,只需看哪个场景更适用。


六、可重入锁和不可重入锁

1)什么是可重入锁和不可重入锁?

同一个线程多次获取同一把锁而不会导致死锁,就是可重入锁;否则就是不可重入锁。

可重入锁中有专门用于记录锁的持有线程和加锁次数的属性。

可重入锁也叫递归锁。

2)可重入锁和不可重入锁分别有什么具体的实现?

Java 中,以 Reentrant 开头命名的锁都是可重入锁;JDK 中提供的 Lock 实现类,包括 synchronized 关键字,都是可重入锁。

Linux 系统提供的 mutex 是不可重入锁。


七、读写锁

1)多线程对同一共享数据进行读写的三种情况

<1>多个线程同时读同一共享数据,不会产生线程安全问题;

<2>多个线程同时写同一共享数据,会产生线程安全问题;
<3>多个线程一边读,一边写同一共享数据,也会产生线程安全问题;
2)为什么要有读写锁?

从上文可以看出,多线程同时读的操作并不会产生线程安全问题,而在实际开发中,这种读操作是十分频繁的,如果使用和后两种情况一样“重量”的锁,那么就会有非常多的资源开销和性能浪费。因此,如果讲读锁和写锁分开,那么就可将资源开销省下,提升了性能。

3)什么是读写锁?

读锁,就是一个线程加锁的时候,其他线程只能读不能写;

写锁,就是一个线程加锁的时候,其他线程不能读也不能写;

读锁与读锁之间不会出现锁冲突;

写锁和写锁之间会出现锁冲突;

读锁和写锁之间也会出现锁冲突;

读写锁实际上就是把读操作和写操作区分对待了。
4)synchronized 和 ReentrantReadWriteLock

synchronized 不是读写锁。

Java 标准库提供了 ReentrantReadWriteLock 类,实现了读写锁。

ReentrantReadWriteLock.ReadLock 类表示读锁。

ReentrantReadWriteLock.writeLock 类表示写锁。

上述两个锁,都通过 lock() 和 unlock() 方法进行加锁和解锁。


阅读指针 —>《锁进阶 -- synchronized 的锁优化》

链接生成中..........

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

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

相关文章

nginx配置自动压缩-gzip压缩

1.nginx配置文件 server里添加gzip配置信息。 重启nginx服务 对比效果&#xff1a;上图是没有开启gzip自动压缩&#xff0c;总共资源是1.3M&#xff0c;传输1.3MB&#xff0c;下图是开启gzip压缩&#xff0c;总共资源是1.3M&#xff0c;传输了973KB。

2023年华为HCIA认证H12-811题库讲解

在VRP平台上&#xff0c;可以通过下面哪种方式返回到上一条历史命令&#xff1f;&#xff08; &#xff09; A、Ctr1U B、Ctr1P C、左光标 D、上光标 试题答案&#xff1a;BD 试题解析&#xff1a;在VRP系统中&#xff0c;ctrlU为自定义快捷键&#xff0c;ct…

网工内推 | 项目经理专场,最高20K*13薪,软考证书优先

01 Trasen 招聘岗位&#xff1a;大项目经理&#xff08;医疗行业/HIS&#xff09; 职责描述&#xff1a; 1.负责项目按计划完成交付并顺利验收结项&#xff1b; 2.参与项目前期预算、评审、方案设计等&#xff1b; 3.负责具体项目实施&#xff0c;制定项目计划、组织项目资源、…

2022年拉丁美洲中东和非洲医疗机器人市场及全球概况报告

今天分享的是机器人系列深度研究报告&#xff1a;《2022年拉丁美洲中东和非洲医疗机器人市场及全球概况报告》。 &#xff08;报告出品方&#xff1a;Apollo Reports&#xff09; 报告共计&#xff1a;195页 研究方法论 2.1通过桌面研究和内部存储库的假设 a)最初&#xff…

Python从入门到精通五:Python数据容器

数据容器入门 为什么学习数据容器 思考一个问题&#xff1a;如果我想要在程序中&#xff0c;记录5名学生的信息&#xff0c;如姓名。 如何做呢&#xff1f; 学习数据容器&#xff0c;就是为了批量存储或批量使用多份数据 Python中的数据容器&#xff1a; 一种可以容纳多份…

记录一下快速上手Springboot登录注册项目

本教程需要安装以下工具&#xff0c;如果不清楚怎么安装的可以看下我的这篇文章 链接: https://blog.csdn.net/qq_30627241/article/details/134804675 管理工具&#xff1a; maven IDE&#xff1a; IDEA 数据库&#xff1a; MySQL 测试工具&#xff1a; Postman 打开IDE…

进程的同步和异步、进程互斥

一、进程同步和异步 同步&#xff08;Synchronous&#xff09;&#xff1a; 同步指的是程序按照顺序执行&#xff0c;一个操作完成后才能进行下一个操作。在多进程或多线程的环境中&#xff0c;同步意味着一个进程&#xff08;或线程&#xff09;在执行某个任务时&#xff0c;…

STM32MP157D-DK1开发板固件烧录

本篇介绍STM32MP157D-DK1开发板如何烧录官方固件。 1 开发板基础硬件介绍 1.1 常用接口 板子上的各种接口功如下&#xff0c;本篇固件烧录&#xff0c;主要用的接口包括&#xff1a; CN6&#xff1a;供电接口B2&#xff1a;复位按键CN11&#xff1a;ST-LINK USB&#xff08…

【QT入门】基础知识

一.认识Qt qt是一套应用程序开发库&#xff0c;与MFC不同是跨平台的开发类库&#xff0c;主要用来开发图形界面。完全面向对象容易扩展。 优点&#xff1a;1.封装性强&#xff0c;简单易学 2.跨平台 3.独立编译为本地代码 二.qt工程 1.常见的工程文件有这两种…

4fiddler抓包工具的使用

一、定义 1.1 抓包的定义 说明&#xff1a;客户端向服务器发送请求以及服务器响应客户端的请求&#xff0c;都是以数据包来传递的。 抓包(packet capture)&#xff1a;通过工具拦截客户端与服务器交互的数据包 1.2 fiddler的介绍 Fiddler是一个http协议调试代理工具&#…

计算机丢失msvcp140dll怎么恢复?快速解决dll缺失问题

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“msvcp140dll丢失”。msvcp140.dll是一个动态链接库文件&#xff0c;它包含了许多C标准库函数的实现。这些动态链接库文件是程序运行所必需的&#xff0c;它们包含了许多函数和资源&#xf…

TCP协议实现一对一聊天与UDP协议实现群聊

tcp一对一聊天&#xff1a; 服务端代码 import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Scanner;/*** 发送消息线程…