Java锁机制

锁的类型

悲观锁 vs 乐观锁

  1. 悲观锁:悲观锁的思想是在操作数据之前先获取锁,认为数据在操作期间可能会被其他事务修改,因此需要先加锁保护数据。
    • 常见的悲观锁实现包括数据库中的行级锁、表级锁、页级锁等,以及Java中的 synchronized 关键字、ReentrantLock 等。
    • 悲观锁的特点是对数据的并发访问持保守态度,可能会导致大量的锁竞争和资源浪费。
  2. 乐观锁:乐观锁的思想是假设数据在操作期间不会被其他事务修改,因此不加锁直接进行操作,但在提交事务时会检查数据是否被其他事务修改过。
    • 常见的乐观锁实现包括数据库中的版本号控制(如MVCC机制)、CAS(Compare and Swap)算法等。
    • 乐观锁的特点是减少了锁竞争和资源浪费,但可能会增加冲突处理的复杂度。

间隙锁

在数据库中,间隙锁(Gap Lock)是一种用于锁定一段范围的记录之间的空间(间隙)的锁。当使用间隙锁时,数据库系统会锁定指定范围内的记录之间的空间,防止其他事务在该范围内插入新记录,从而确保了范围查询的一致性。

具体来说,间隙锁有以下特点和作用:

  1. 范围锁:间隙锁是一种范围锁,它锁定了一段记录之间的空间,而不是具体的记录。这意味着在该间隙范围内的任何记录都无法插入或更新,直到锁释放。

  2. 防止幻读:间隙锁的一个主要作用是防止幻读(Phantom Read)。幻读是指在一个事务中,同样的查询条件在不同的时间点会返回不同数量的记录。通过使用间隙锁,可以阻止其他事务在指定范围内插入新的记录,从而避免了幻读的问题。

  3. 范围查询一致性:当一个事务执行范围查询时,间隙锁可以确保查询结果的一致性,即在查询过程中其他事务无法在查询范围内插入新的记录,从而保证了查询结果的可靠性。

需要注意的是,间隙锁可能会引发死锁问题,特别是在并发量较大的情况下。因此,在使用间隙锁时,需要注意合理设计事务和锁的范围,以避免死锁的发生。

间隙锁常用于数据库中的并发控制。在数据库中,间隙锁通常由数据库引擎自动管理,不需要手动操作。

synchronized

synchronized的使用

synchronized锁的的内容应该是变化的量。

锁定块

//synchronized 关键字,上锁后执行后面的代码
public class T5_Synchronized {public void m(){synchronized (this) {cnt--;System.out.println( Thread.currentThread().getName() + " count = " + cnt );}}
}

锁定方法

//synchronized 关键字,上锁后执行后面的代码
public class T6_Synchronized {//等价于synchronized(T6_Synchronized.class)public synchronized void m(){System.out.println( Thread.currentThread().getName() + " count = " + cnt );}
}

synchronized原理

  • 互斥性: synchronized提供了互斥性,即一次只允许一个线程进入被Syn锁住的代码块或方法。当一个线程获取到Syn锁时,其他线程会被阻塞,直到该线程释放锁。
  • 可见性: synchronized还提供了可见性,即当一个线程修改了被synchronized保护的共享变量时,修改对其他线程是可见的。这是因为当一个线程释放Syn锁时,会强制刷新缓存,使得其他线程可以看到最新的共享变量值。
  • 内存模型屏障: 在Java内存模型中,synchronized还会通过内存模型屏障来确保代码的顺序性。在获取和释放锁的过程中,会插入相应的内存屏障指令,以防止编译器或处理器对代码进行重排序,确保代码执行顺序符合预期。

当一个线程获取某个类的Syn锁时,发生以下情况:

  • 获取锁: 线程尝试获取该类的Syn锁。如果锁可用,线程将立即获得锁,并继续执行同步代码块或方法;如果锁不可用,则线程进入阻塞状态,直到锁可用为止。
  • 锁竞争: 如果多个线程同时竞争同一个类的Syn锁,只有一个线程能够获取锁,其他线程将被阻塞在锁获取的过程中,直到锁被释放。
  • 执行同步代码: 一旦线程获取到锁,它就可以执行同步代码块或方法。在执行同步代码期间,其他线程无法访问被synchronized保护的共享资源。
  • 释放锁:当线程执行完同步代码块或方法后,会释放锁。这样其他等待的线程就有机会获取锁,并执行同步代码。

总的来说,当一个线程锁住某个类时,它会尝试获取该类的Syn锁,如果成功获取锁,则可以执行同步代码,否则会被阻塞直到获取到锁为止。一旦线程执行完同步代码,它会释放锁,让其他等待的线程有机会获取锁。

ReentrantLock(可重入锁)

ReentrantLock是Java中的一种独占锁(也称为互斥锁),它可以用于实现对共享资源的线程安全访问。与使用synchronized关键字实现的隐式锁相比,ReentrantLock提供了更多的灵活性和功能。

主要特点包括:

  1. 可重入性:与synchronized类似,ReentrantLock是可重入的,同一个线程可以多次获取同一把锁而不会导致死锁。

  2. 公平性ReentrantLock可以选择是否公平地获取锁。在公平模式下,锁将按照线程的请求顺序分配。在非公平模式下,锁将会尝试立即获取锁,而不管其他线程是否在等待。

  3. 等待可中断ReentrantLock支持在等待锁的过程中响应中断。线程可以在等待锁时被其他线程中断,而不是一直等待下去。

  4. 超时获取锁ReentrantLock支持尝试在一定时间内获取锁,如果获取不到则放弃。

  5. 条件变量ReentrantLock提供了Condition接口,可以通过newCondition()方法创建条件对象,用于线程间的协调和通信。

  6. 释放:使用ReentrantLock时需要确保在finally块中释放锁,以防止发生死锁。

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class Example {private final Lock lock = new ReentrantLock();public void doSomething() {lock.lock(); // 获取锁try {// 执行需要同步的代码块} finally {lock.unlock(); // 释放锁}}
}

注意:

try块中避免使用return语句,以免出现意外的逻辑错误。

如果在try块中使用了return语句,而在finally块中释放锁,那么会发生以下情况:

  1. return语句在finally块之前执行:在try块中的return语句执行时,会将结果返回给调用者,但此时finally块尚未执行。如果在finally块中释放锁,那么在return语句执行完毕后才会执行finally块中的释放锁操作。
    public class Example {private final Lock lock = new ReentrantLock();public int getValue() {lock.lock(); // 获取锁try {return 10;} finally {lock.unlock(); // 释放锁}}
    }
    
  2. 在finally块中return:在finally块中使用return语句,会导致在try块中的return语句失效,实际返回的结果是在finally块中的return语句返回的结果。
    public class Example {private final Lock lock = new ReentrantLock();public int getValue() {lock.lock(); // 获取锁try {return 10;} finally {lock.unlock(); // 释放锁return 20; // 这个return语句会覆盖try块中的return语句}}
    }
    

辨析

synchronized

  • 关键字。
  • Java 中最基本的线程同步机制之一。
  • 通过 JVM 实现,无需额外的 API 调用。
  • 不能中断一个正在试图获得锁的线程。
  • 不支持超时等待。
  • 性能较低,对于大规模并发访问同步代码块时,性能可能会有所下降。
  • 适用于简单的线程同步需求,且锁的范围较小的情况。

Lock

  • 接口,位于 java.util.concurrent.locks 包中。
  • 提供了更灵活的线程同步机制,具有更多的功能。
  • 支持中断等待线程、支持超时等待。
  • 可以获取锁的持有情况,可以尝试获取锁而不会一直等待。
  • 可以创建公平锁(按照等待时间或线程优先级来获取锁)。
  • 可以与条件变量一起使用。
  • 适用于对线程同步需求较为复杂、灵活性较高的情况。

ReentrantLock

  • Lock 接口的实现类之一,也位于 java.util.concurrent.locks 包中。
  • 是可重入锁,支持同一个线程重复获取锁,避免死锁。
  • 提供了更多的功能,如公平锁、可中断锁等。
  • 需要显式地进行锁的获取和释放,相对于 synchronized 更为灵活,但也更容易出错。
  • 适用于对锁的粒度要求较高,需要更精细的控制的情况。

常见的应用场景:

  • synchronized:适用于简单的线程同步需求,例如对实例方法或代码块进行同步,保护共享资源的读写等。

  • Lock:适用于对线程同步需求较为复杂的情况,例如需要支持中断、超时等待、公平锁等功能的场景。

  • ReentrantLock:适用于需要可重入锁和更高级功能的情况,例如需要在同一个线程中多次获取同一个锁的情况,或需要公平锁、可中断锁等功能的场景。

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

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

相关文章

HackmyVM-----Boxing靶机

文章目录 正常打靶流程1.获取靶机IP地址2.获取靶机端口服务3.访问网页4.添加域名WindowsLinux 5.访问域名6.nc反弹shell 7.结束 正常打靶流程 1.获取靶机IP地址 ┌──(root㉿kali)-[/home/kali] └─# arp-scan -l Interface: eth0, type: EN10MB, MAC: 00:0c:29:10:3c:9b, …

Drive Scope for Mac:硬盘健康监测分析工具

Drive Scope for Mac是一款专为Mac用户设计的硬盘健康监测与分析工具,致力于保障用户的数据安全。这款软件功能强大且操作简便,能够实时检测硬盘的各项指标,帮助用户及时发现并解决潜在问题。 Drive Scope for Mac 1.2.23注册激活版下载 Driv…

linux 驱动-匹配2 (amba_bustype)

目录 1.实例分析 a. 设备树实例 b. 驱动实例 2. amba匹配流程 a. 创建amba_device b. 确定总线以及总线的匹配函数 c. 分析总线的匹配函数 1.实例分析 a. 设备树实例 serial7e201000 { compatible "brcm,bcm2835-pl011\0arm,pl011\0arm,primecell"; //创建am…

用Python自动化操作PPT,看完这篇文章就够了!

1.PPT自动化能干什么?有什么优势? 它可以代替你自动制作PPT它可以减少你调整用于调整PPT格式的时间它可以让数据报告风格一致总之就是:它能提高你的工作效率!让你有更多时间去做其他事情! 2.使用win32com操作ppt 官…

【探索Linux】P.32(自定义协议)

阅读导航 引言一、自定义协议概念二、自定义协议需要注意的事项三、自定义协议示例(跨网络计算器协议)✅协议代码(Protocol.hpp)1. 计算器协议简单介绍2. 序列化部分3. 反序列化部分4. 请求和响应数据结构5. 使用自定义协议 四、总结温馨提示 引言 在上…

Rust Tracing 入门

Tracing 是一个强大的工具,开发人员可以使用它来了解代码的行为、识别性能瓶颈和调试问题。 Rust 是一种以其性能和安全保证而闻名的语言,在它的世界中,跟踪在确保应用程序平稳高效运行方面发挥着至关重要的作用。 在本文中探讨Tracing 的概…

C++ 初识模板

目录 0.前言 1.泛型编程 2.函数模板 2.1概念 2.2格式 2.3原理 2.4函数模板的实例化 2.4.1隐式实例化 2.4.2显式实例化 2.5模板参数的匹配原则 3.类模板 3.1类模板的定义格式 3.2类模板的实例化 4.结语 (图像由AI生成) 0.前言 在 C 中&a…

Unity3D 爆火的休闲益智游戏工程源码/3D资源 大合集

Unity3D休闲益智游戏工程源码大合集 一、关卡类游戏工程源码二、跑酷类游戏工程源码三、消除合成类游戏工程源码四、棋牌类游戏工程源码五、RPG(角色扮演)类游戏工程源码六、FPS(射击)类游戏工程源码十、Unity3D工艺仿真六、Unity游戏资源1、Unity3D 吃鸡…

Redis数据类型——String

Redis官网指令文档:Commands | Docs 前言 此处的String类型是针对Redis的Value的,因为Key的形式都是String,而Value则有哈性、列表、集合等形式。 众所周知,由于不同编码,经常会出现乱码的问题,但在Redi…

打造稳定安全的亚马逊测评环境:关键步骤与要点一览

亚马逊测评环境的搭建是一项既复杂又需要深入细致考虑的工作,它涉及多方面的技术配置和资源准备。以下是一些关键步骤和要点,帮助您更高效地构建测评环境。 一、资源筹备 1. 养号系统:选择稳定、高效的养号系统,确保能够模拟真实…

Linux系统-进程和计划任务管理

一.程序和进程 1.程序 保持在硬盘、光盘等介质中的可执行代码和数据文件中静态保存的代码 2.进程 在CPU及内存中运行的程序代码动态执行的代码父、子进程每个程序可以创建一个或多个进程 3.进程特征 动态性:进程是程序的一次执行过程,是临时的&…

决策树分类任务实战(python 代码详解)

目录 一、导入库、数据集、并划分训练集和测试集 二、参数调优 (一)第一种调参方法:for循环 (1)单参数优化 ①单参数优化(无K折交叉验证) ②单参数K折交叉验证 优化 (2)多参数优化 ①多参数优化(无K折交叉验证) 参数介绍: ②多参数K折交叉验证…

vulfocus靶场名称: apache-cve_2021_41773/apache-cve_2021_42013

Apache HTTP Server 2.4.49、2.4.50版本对路径规范化所做的更改中存在一个路径穿越漏洞,攻击者可利用该漏洞读取到Web目录外的其他文件,如系统配置文件、网站源码等,甚至在特定情况下,攻击者可构造恶意请求执行命令,控…

记录一下hive启动metestore服务时报错

【背景说明】 之前hadoop有问题,把hadoop和MySQL删了重装,hive没有动,然后启hive的metastore服务的时候,显示找不到metastore数据库 【报错】 Caused by: java.lang.reflect.InvocationTargetExceptionat sun.reflect.Generated…

【Java框架】SpringMVC(一)——基本的环境搭建及基本结构体系

目录 MVC模式视图(View)控制器(Controller)模型(Model)JSP Model1JSP Model2MVC的优点MVC的缺点 Spring MVC架构介绍特点 SpringMVC环境搭建(在前面Spring整合Mybatis的基础上)1.创建控制器Controller2.创建springmvc配置文件,并添加Controller的Bean3.web.xml中配置…

# 从浅入深 学习 SpringCloud 微服务架构(二)模拟微服务环境(1)

从浅入深 学习 SpringCloud 微服务架构(二)模拟微服务环境(1) 段子手168 1、打开 idea 创建父工程 创建 artifactId 名为 spring_cloud_demo 的 maven 工程。 --> idea --> File --> New --> Project --> Ma…

2024 CKA 最新 | 基础操作教程(十七)

题目内容 设置配置环境: [candidatenode-1] $ kubectl config use-context ek8s Task 将名为 node02 的 node 设置为不可用,并重新调度该 node 上所有运行的 pods。 考点相关内容分析 node 在 Kubernetes(K8s)中&#xff0c…

VASA-1:一键生成高质量视频,颠覆你的想象!

VASA-1:语音生成AI视频 前言 最近,微软公司公布了一项图生视频的 VASA-1 框架,该 AI 框架只需使用一张真人肖像照片和一段个人语音音频,就能够生成精确逼真的相对应文本的视频,而且可以使表情和面部动作表现的十分自然…

【数据结构】栈和队列(链表模拟队列)

学习本章节必须具备 单链表的前置知识, 建议提前学习:点击链接学习:单链表各种功能函数 细节 详解 本章节是学习用 单链表模拟队列 1. 单链表实现队列 思路如下 队列:只允许在一端进行插入数据操作,在另一端进行删除数…

线程互斥及基于线程锁的抢票程序

我们实现一个简单的多线程抢票程序。 #include<iostream> #include<thread> #include<unistd.h> #include<functional> #include<vector> using namespace std; template<class T> using func_tfunction<void(T)>;//返回值为void,…