我的编程空间,编程开发者的网络收藏夹
学习永远不晚

【JavaEE】锁策略

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

【JavaEE】锁策略

在这里插入图片描述

文章目录

前言

在前面的多线程中,我们学习了为了解决线程不安全问题,使用 synchronized 为线程进行加锁,但是作为程序员光知道如何使用锁还不行,还需要知道有哪些锁策略。今天我将为大家分享在多线程中有哪些锁策略。

1. 乐观锁和悲观锁

悲观锁是一种基于悲观态度的锁机制,它假定最坏的情况,即在修改数据之前,它会先将数据锁住,阻止任何人对数据进行操作,直到它释放锁。这种锁的机制可以完全保证数据的独占性和正确性,因为每次请求都会先对数据进行加锁,然后进行数据操作,最后再解锁。然而,由于加锁和解锁的过程会造成消耗,所以这种策略的性能不高。

乐观锁则是一种基于乐观态度的锁机制,它假定不会发生数据冲突,只在提交操作的时候才锁定数据。这意味着,在数据提交之前,其他进程可以继续对数据进行操作。乐观锁可以实现并行操作,因此具有较高的性能。但需要注意的是,如果发生数据冲突,需要由数据库系统进行处理。

在这里插入图片描述

乐观锁和悲观锁都是计算机对后面发生事情的预测。悲观锁会觉得后面发生锁冲突的现象比较严重,所以在修改数据之前就会上锁;而乐观锁则觉得后面发生锁冲突的现象不严重,所以在处理数据之前就不会进行加锁。

给大家举个简单的例子:加入我们刚来到一个城市,周末的时候我想去体育馆打篮球,但是因为是刚来,不知道体育馆几点开门。那么这时候,悲观锁的做法就是:我现在家等着吧,问问朋友体育馆啥时候开门,但是朋友可能还在睡觉,所以我就只能在家等着;而乐观锁则是:”现在都8点了,体育馆应该开门了,我先过去,如果开门了就可以直接进去了,就算没开门,我也可以在体育馆外面等一会“。

2. 重量级锁和轻量级锁

重量级锁和轻量级锁是站在工作量的角度来划分的。

重量级锁基于操作系统的互斥量(Mutex Lock)而实现的锁,会导致进程在用户态和内核态之间切换,相对开销较大。例如,synchronized在内部基于监视器锁(monitor)实现,监视器锁基于底层的操作系统的Mutex Lock实现,因此在这种情况下synchronized属于重量级锁,重量级锁需要在用户态和核心态之间做转换。

  • 大量的内核态用户态切换
  • 很容易引发线程的调度

轻量级锁则是相对与重量级锁而言的,轻量级锁的核心设计实在没有多线程竞争的前提下,减少重量级锁的使用以提高系统性能。 轻量级锁适用于线程交替执行同步代码块的情况(既互斥操作),如果同一时刻与多个线程访问同一个锁,则将会导致轻量级锁膨胀为重量级锁。轻量级锁在发生线程竞争时,会让出 CPU 的执行权限,以便其他线程可以继续工作。

  • 少量的内核态用户态切换.
  • 不太容易引发线程调度

为什么重量级锁的用户态和内核态之间的转换效率会更低呢?

用户态的读写速率比内核态更慢。在内核态,CPU可以访问内存的所有数据,包括外围设备如硬盘、网卡等。同时,CPU也可以将自己从一个程序切换到另一个程序。而在用户态,程序只能受限地访问内存,且不允许访问外围设备。这种情况下,如果用户态的程序需要访问外围设备,如硬盘,那么它必须先切换到内核态,再由内核态进行系统调用来读写磁盘,这个过程会导致额外的开销。

为什么内核态操作与用户态的操作相比效率较低呢?

内核态的实现会占用内核稀缺的资源,例如操作系统需要维护线程列表,一旦操作系统装载后就无法动态改变。并且线程的数量远远大于进程的数量,随着线程数的增加,内核将耗尽,从而导致效率降低。此外,每次线程切换到内核态都需要陷入到内核,由操作系统来调度,这个过程也会花费一定的时间。

3. 自旋锁和挂起等待锁

自旋锁是一种轻量级锁,当一个线程尝试获取锁失败时,它会一直循环尝试获取锁,直到成功为止。这种机制消耗大量的CPU资源,因为它会使线程不断地尝试获取锁,无法做其他的工作。自旋锁只在加锁失败时进行忙等待,不会阻塞线程。

//这是一个自旋锁的伪代码//当getLocker的返回结果为false的时候,表示未获取到锁,那么就继续循环while(getLocker == false) {  }

挂起等待锁是重量级锁的一种典型实现。当一个线程尝试获取锁失败时,它会通过内核的机制挂起等待,直到锁被释放。此时,线程会释放CPU资源,让其他线程可以执行。当锁被释放时,挂起的线程会重新尝试获取锁。挂起等待锁在等待期间会阻塞线程,导致线程无法做其他的工作。

//挂起等待锁,未获取到锁则是进入阻塞等待,等待内核态操作获取到锁synchronized (locker) {}

自旋锁虽然会消耗 CPU 资源,但换来的是更快的响应速度。

这两种锁的选用取决于具体的应用场景和需求。如果线程间的交互非常频繁,且锁被持有的时间比较短,那么自旋锁可能更合适。如果线程间的交互比较少,且锁被持有的时间比较长,那么挂起等待锁可能更合适。

当线程想要获取锁但是这个锁又被别的线程获取到的时候,挂起等待锁会进入阻塞等待状态,因为进入阻塞的线程什么时候被唤醒是个不确定因素,它是由内核态操作决定的,所以就会导致程序的执行速度下降;而自旋锁则不会进入阻塞等待状态,而是不断循环判断这个锁时候还被占有,如果这个锁还被占有,那么自旋锁还会继续循环,直到这个锁被释放,当这个锁被释放的时候该线程就可以获取到该锁,保证了整个操作都处于用户态的操作。

4. 公平锁和非公平锁

公平锁和非公平锁是两种常用的线程同步机制,用于在多线程环境下保护共享资源。

公平锁是指多个线程按照请求锁的顺序获取锁,即先到先得的原则。在公平锁中,如果有多个线程等待获取锁,那么锁会依次分配给等待时间最长的线程,这样可以避免线程饥饿的情况。公平锁的实现比较复杂,需要维护一个线程等待队列,因此性能会比较低。

非公平锁是指多个线程按照竞争获取锁的顺序获取锁,即先到不一定先得的原则。在非公平锁中,如果有多个线程等待获取锁,那么锁可能会直接分配给等待时间较短的线程,这样可能会导致一些线程一直无法获取锁,出现线程饥饿的情况。非公平锁的实现比较简单,不需要维护一个线程等待队列,因此性能会比较高。

5. 可重入锁和非可重入锁

可重入锁是指同一个线程在外层方法获取锁的时候,再进入该线程的内层方法会自动获取锁(前提是锁对象得是同一个对象),不会因为之前已经获取过锁还没有释放而阻塞。可重入锁的一个优点是可以避免死锁。

非可重入锁则是相反,线程获取锁后,内部不能再获取锁,由于之前已经获取过还没释放而阻塞,可能会导致线程死锁。

6. 读写锁

我们通常对数据的操作就是读操作和写操作,如果是单线程的话,读和写操作不会发生问题,但是如果发生在多线程当中的话就会出现一些问题,当我一个线程在读数据的时候,另一个线程在写这个数据,那么到最后读取的数据就与数据本身不一样;当两个线程都进行写操作的时候,最终的结果也不是正确的结果,而多个线程同时进行读操作的时候是不会发生问题的。也就是说只有多个线程同时进行读操作的时候才不会发生线程安全的问题,那么该如何解决读操作和写操作在多线程中出现的问题呢?

读写锁,当多个线程同时进行读操作的时候不会发生互斥的问题,如果多个线程同时进行读操作和写操作或者同时进行写操作的时候,读写锁就是互斥的,后面的线程就无法获取到这个锁。

读写锁的特点是:

  1. 读读不互斥:多个线程可以同时读取共享资源,因为读操作本身是线程安全的。
  2. 读写互斥:当有一个线程正在写共享资源时,其他线程不能进行读或写操作,因为读写操作是互斥的,以防止数据不一致或数据竞争。
  3. 写写互斥:当有两个或多个线程同时写共享资源时,会产生互斥现象,以防止数据互相干扰。

Java synchronized 分别对应哪些锁策略

1. 乐观锁和悲观锁

对于乐观锁和悲观锁来说, synchronized 属于自适应锁。synchronized 一开始属于乐观锁,但是如果计算机预测到后面发生锁冲突的现象较严重的话,synchronized 就会转变为悲观锁。

2. 重量级锁和轻量级锁

对于重量级锁和轻量级锁来说,synchronized 也是属于自适应锁。开始由于线程的工作量较小,synchronized 是轻量级锁,但是如果到后面线程需要处理的工作量较大的话,synchronized 又会转变为重量级锁。

3. 自旋锁和挂起等待锁

对于自旋锁和挂起等待锁来说,synchronized 属于自适应锁。当锁冲突的现象不严重的时候,synchronized 为自旋锁,但是如果锁冲突现象较严重的话,synchronized 又会转换为挂起等待锁。

4. 公平锁和非公平锁

synchronized 属于非公平锁,当多个线程尝试获取同一把锁的时候,synchronized 不管你先来后到的顺序,而是所有等待的线程竞争这把锁。

5. 可重入锁和非可重入锁

synchronized 属于可重入锁,当一个线程在外面获取到这个锁的时候,在内部也会自动获取到这个锁,而不会陷入死锁的状态。

synchronized 不属于读写锁。

相关面试题

1) 你是怎么理解乐观锁和悲观锁的,具体怎么实现呢?

悲观锁认为多个线程访问同一个共享变量冲突的概率较大, 会在每次访问共享变量之前都去真正加锁。

乐观锁认为多个线程访问同一个共享变量冲突的概率不大. 并不会真的加锁, 而是直接尝试访问数据. 在访问的同时识别当前的数据是否出现访问冲突.

悲观锁的实现就是先加锁(比如借助操作系统提供的 mutex), 获取到锁再操作数据. 获取不到锁就等待.

乐观锁的实现可以引入一个版本号. 借助版本号识别出当前的数据访问是否冲突.

2) 介绍下读写锁?

  • 读写锁就是把读操作和写操作分别进行加锁.
  • 读锁和读锁之间不互斥.
  • 写锁和写锁之间互斥.
  • 写锁和读锁之间互斥.
  • 读写锁最主要用在 “频繁读, 不频繁写” 的场景中.

3) 什么是自旋锁,为什么要使用自旋锁策略呢,缺点是什么?

如果获取锁失败, 立即再尝试获取锁, 无限循环, 直到获取到锁为止. 第一次获取锁失败, 第二次的尝试会在极短的时间内到来. 一旦锁被其他线程释放, 就能第一时间获取到锁.

相比于挂起等待锁,

优点: 没有放弃 CPU 资源, 一旦锁被释放就能第一时间获取到锁, 更高效. 在锁持有时间比较短的场景下非常有用.

缺点: 如果锁的持有时间较长, 就会浪费 CPU 资源

4) synchronized 是可重入锁么?

是可重入锁.

可重入锁指的就是连续两次加锁不会导致死锁.

实现的方式是在锁中记录该锁持有的线程身份, 以及一个计数器(记录加锁次数). 如果发现当前加锁的线程就是持有锁的线程, 则直接计数自增.

来源地址:https://blog.csdn.net/m0_73888323/article/details/133418184

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

【JavaEE】锁策略

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

MySQL锁在INSERT操作中的锁策略调整

在MySQL中,INSERT操作涉及到的锁主要有表级锁和行级锁。对于InnoDB存储引擎,它默认使用行级锁,因此在INSERT操作中会对插入的行进行加锁。如果在INSERT操作中出现了锁相关的性能问题,可以考虑调整锁策略来改善性能。以下是
MySQL锁在INSERT操作中的锁策略调整
2024-08-19

MySQL锁机制在INSERT中的锁管理策略

MySQL在INSERT操作时,会涉及到锁的管理策略,主要有以下几种:表锁(Table Lock):在某些情况下,MySQL会对整个表进行锁定,以防止其他事务对表的修改。当执行INSERT操作时,如果表级锁已经存在,其他事务将被阻塞,直到当
MySQL锁机制在INSERT中的锁管理策略
2024-08-14

MySQL 并发控制中的锁策略

MySQL 锁的并发控制策略引言:在数据库系统中,为了保证数据的一致性和完整性,需要对并发操作进行控制。而锁机制是一种常用的并发控制策略。MySQL作为一种常用的关系数据库管理系统,也拥有自己的锁机制,下面我们就来详细了解MySQL锁的并发
MySQL 并发控制中的锁策略
2023-12-21

MySQL INSERT锁与数据库备份策略

当在MySQL数据库中进行INSERT操作时,会涉及到表级锁和行级锁。表级锁:当执行INSERT操作时,MySQL会自动获取表级写锁,锁定整张表,确保在插入数据时其他操作无法同时对表进行写操作。这会导致其他操作在同一时间无法对表做任何写入操
MySQL INSERT锁与数据库备份策略
2024-08-19

MySQL INSERT锁与数据库安全策略

MySQL的INSERT锁是一种行级锁,用于确保在插入新行时的并发性。如果多个客户端尝试同时向同一个表中插入数据,MySQL会使用INSERT锁来确保每个客户端都能成功插入数据,并且数据不会被覆盖或丢失。在数据库安全策略方面,除了使用IN
MySQL INSERT锁与数据库安全策略
2024-08-19

MySQL锁在INSERT操作中的锁冲突避免策略

在MySQL中,INSERT操作可能会引起锁冲突,主要是由于表的锁和行级锁导致的。以下是一些避免锁冲突的策略:使用InnoDB存储引擎:InnoDB存储引擎支持行级锁,可以减少锁冲突的可能性。尽量避免长时间锁定:在进行INSERT操作时,尽
MySQL锁在INSERT操作中的锁冲突避免策略
2024-08-13

MySQL锁在INSERT操作中的锁策略调整原则

在MySQL中,INSERT操作会涉及到表级锁和行级锁。根据不同的情况,我们可以调整锁的策略来确保并发性能和数据一致性。以下是一些调整MySQL锁在INSERT操作中的策略的原则:如果表中存在大量的并发INSERT操作,可以考虑使用Inn
MySQL锁在INSERT操作中的锁策略调整原则
2024-08-13

MySQL插入锁与数据库缓存策略

MySQL中的插入锁是指在插入数据时对被插入的数据行进行锁定,以防止其他并发操作对该数据行的修改或删除。这样可以保证数据的完整性和一致性。数据库的缓存策略是指数据库系统对数据的读取和写入进行缓存管理,以提高系统的性能和效率。数据库缓存通常
MySQL插入锁与数据库缓存策略
2024-08-19

用组策略轻松锁定Windows XP任务栏

我们在使用Windows XP的过程中,经常会不小心把原本在底部的任务栏拉到上方或隐藏,要想把它拉回原位置还要颇费一番周折。有没有简单的方法让任务栏固定不动呢?有,让我们用OJglbbAjx组策略把它锁定吧。方法如下:   用鼠标左键单击&
2023-05-24

MySQL INSERT锁与数据库应用部署策略

在MySQL中,INSERT操作会涉及到行级锁和表级锁。当一个INSERT操作在执行时,会自动给相关的行或表加锁,以确保数据的一致性和完整性。对于数据库的应用部署策略,可以考虑以下几点来避免INSERT锁带来的影响:合理设计数据库表结构:
MySQL INSERT锁与数据库应用部署策略
2024-08-13

阿里云服务器锁定问解决策略

本文将详细介绍如何解决阿里云服务器被锁定的问题,包括锁定的原因、解决步骤以及注意事项。阿里云服务器锁定问题是指在使用阿里云服务器时,由于各种原因导致服务器被锁定,无法正常使用。这可能会导致数据丢失,甚至影响业务运行。下面我们将详细探讨如何解决这个问题。一、锁定原因账户异常:如账户被冻结或被限制使用。错误操作:如未
阿里云服务器锁定问解决策略
2024-01-25

MySQL INSERT锁与数据库缓存失效策略

在MySQL中,INSERT操作可能会导致锁定表或行,这取决于表的存储引擎和事务的隔离级别。当执行INSERT操作时,MySQL会在需要的情况下锁定相应的表或行,以确保数据的一致性和完整性。如果在执行INSERT操作时遇到锁定问题,可以考
MySQL INSERT锁与数据库缓存失效策略
2024-08-14

S/4 HANA中的数据库锁策略是什么

本篇文章给大家分享的是有关S/4 HANA中的数据库锁策略是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。S4 中的新的 MM 数据模型以及 HANA 的 Insert-o
2023-06-04

JavaHibernate中的查询策略和抓取策略

Hibernate是一种Java对象关系映射框架,提供了多种查询和抓取策略,用于优化数据库访问性能。查询策略包括延迟加载、立即加载、查询缓存等,抓取策略包括join抓取、子查询抓取、批量抓取等。这些策略可以根据实际应用场景进行选择和配置,提高数据访问的效率和稳定性
2023-05-18

剖析6个MySQL死锁案例的原因以及死锁预防策略

MySQL 死锁是面试常问问题,金三银四,所以最近面试相关的文章比较多,本文章是总结的一波死锁问题,和大家分享一下。 Mysql 锁类型和加锁分析 MySQL有三种锁的级别:页级、表级、行级。 **表级锁:**开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲
剖析6个MySQL死锁案例的原因以及死锁预防策略
2015-02-16

Oracle中表锁定的调优策略和注意事项

Oracle中表锁定是在进行数据操作时对表进行加锁,以确保数据的一致性和完整性。在数据库中,表锁定是一种重要的控制机制,但如果不恰当使用会造成性能问题。因此,在进行表锁定时,需要注意一些调优策略和注意事项,以提高数据库性能和减少锁定带来的影
Oracle中表锁定的调优策略和注意事项
2024-03-03

MySQL INSERT锁与数据库查询性能调优策略

使用批量插入数据:在插入大量数据时,可以考虑使用批量插入数据的方式,减少插入操作的次数,提高插入性能。使用LOAD DATA INFILE:如果需要导入大量数据到数据库中,可以考虑使用MySQL提供的LOAD DATA INFILE语句,效
MySQL INSERT锁与数据库查询性能调优策略
2024-08-14

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录