当前位置: 首页 > news >正文

【Java 基础】21 多线程同步与锁

文章目录

    • 1.存在的问题
    • 2.使用同步解决问题
      • 1) synchronized
      • 2) volatile
      • 3) 锁
    • 总结

用多线程过程中,有可能出现 多个线程同时处理(获取或修改等)同一个数据,这个时候就 会发生数据不同步的问题, 因此出现了同步和锁来保证多个线程可以安全的处理同一个数据。

1.存在的问题

例如:火车售票窗口售票,假如我们有 2 个窗口(相当于开启了 2 个线程),同时卖 10 张票
在这里插入图片描述

两个窗口的操作流程都如下:

1)购票者到窗口

2)窗口访问票匣子获取余票数量

3)票匣子返回余票数量

4)售票窗口判断,若存在票(大于 0 )则卖给他

那么,假如票匣子就剩下 1 张票啦!但是不巧的是两个窗口同时查看余票数量,都发现还有 1 张票,**又都卖给了购票者……**这就是多线程存在的数据不同步问题_

示例代码:

public class Demo {public static void main(String[] args) throws InterruptedException {ThreadDemo threadDemo = new ThreadDemo();new Thread(threadDemo,"售票窗口1").start();new Thread(threadDemo,"售票窗口2").start();}
}class ThreadDemo implements Runnable {private int ticketCount = 10;@Overridepublic void run() {String tName = Thread.currentThread().getName();while (true) {if (ticketCount <= 0) {return;}try {Thread.sleep(200);System.out.println(tName + "成功卖了一张票!余票:" + (ticketCount-- - 1));} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}

输出结果:

售票窗口1成功卖了一张票!余票:9
售票窗口2成功卖了一张票!余票:8
售票窗口1成功卖了一张票!余票:7
售票窗口2成功卖了一张票!余票:6
售票窗口2成功卖了一张票!余票:5
售票窗口1成功卖了一张票!余票:4
售票窗口2成功卖了一张票!余票:3
售票窗口1成功卖了一张票!余票:2
售票窗口1成功卖了一张票!余票:1
售票窗口2成功卖了一张票!余票:0
售票窗口1成功卖了一张票!余票:-1

2.使用同步解决问题

同步(Synchronization) 是一种协调多个线程执行的机制,它能够确保在同一时刻只有一个线程访问共享资源。主要通过关键字 synchronizedvolatile 以及 锁对象 等手段来实现同步。

1) synchronized

关键字 synchronized 用于修饰方法或代码块,保证在同一时刻只有一个线程能够执行被 synchronized 修饰的代码。以下是两种使用方式:

  • 修饰方法
public synchronized void test() {// 同步的代码块
}
  • 修饰代码块
public void someMethod() {// 非同步的代码块synchronized (lockObject) {// 同步的代码块}// 非同步的代码块
}

2) volatile

关键字 volatile 用于声明变量,保证变量的可见性。被 volatile 修饰的变量对所有线程可见,当一个线程修改了这个变量的值,其他线程能够立即看到修改后的值。

public class Demo {private volatile int ticketCount = 10;
}

3) 锁

Java 提供了很多种锁,常用的有 synchronized 关键字、ReentrantLockRead/Write Lock 等 。

  • ReentrantLock

    它支持可重入锁,允许一个线程多次获取同一把锁。

    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;public class Demo {private final Lock lock = new ReentrantLock();public void test() {lock.lock();try {// 同步的代码块} finally {lock.unlock();}}
    }
    

    ReentrantLock 提供了比 synchronized 更丰富的功能,如可中断锁、公平锁、定时锁等

  • Read/Write Lock

    ReadWriteLock 接口定义了读写锁,它包含两个锁,一个用于读操作,一个用于写操作。读写锁允许多个线程同时读取共享资源,但只允许一个线程进行写操作。ReentrantReadWriteLockReadWriteLock 的一个实现类

    import java.util.concurrent.locks.ReadWriteLock;
    import java.util.concurrent.locks.ReentrantReadWriteLock;public class Demo {private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();public void read() {readWriteLock.readLock().lock();try {// 读取共享资源的操作} finally {readWriteLock.readLock().unlock();}}public void write() {readWriteLock.writeLock().lock();try {// 修改共享资源的操作} finally {readWriteLock.writeLock().unlock();}}
    }
    

    读写锁适用于读操作远远多于写操作的场景,可以提高并发性

  • StampedLock

    它是一种读写锁的变种,提供了乐观读锁,可以在读多写少的场景中提供更好的性能

    import java.util.concurrent.locks.StampedLock;public class Demo {private final StampedLock stampedLock = new StampedLock();public void read() {long stamp = stampedLock.tryOptimisticRead();// 乐观读操作if (!stampedLock.validate(stamp)) {// 有写操作发生,转为悲观读stamp = stampedLock.readLock();try {// 悲观读操作} finally {stampedLock.unlockRead(stamp);}}}public void write() {long stamp = stampedLock.writeLock();try {// 写操作} finally {stampedLock.unlockWrite(stamp);}}
    }
    

    StampedLock 提供了更细粒度的控制,并允许在不同的代码路径中执行不同的操作

总结

在多线程编程中,确保线程安全是至关重要的!通过合理使用 synchronized 关键字、volatile 关键字以及 ReentrantLock 等锁机制,可以有效地保护共享资源,避免数据不一致和竞态条件等问题。合理的同步机制不仅能够提高程序的性能,还能够确保程序的正确性。在实际开发中,根据具体场景选择合适的同步和锁机制是编写高效、安全多线程代码的关键。

相关文章:

【Java 基础】21 多线程同步与锁

文章目录 1.存在的问题2.使用同步解决问题1) synchronized2) volatile3) 锁 总结 用多线程过程中&#xff0c;有可能出现 多个线程同时处理&#xff08;获取或修改等&#xff09;同一个数据&#xff0c;这个时候就 会发生数据不同步的问题&#xff0c; 因此出现了同步和锁来…...

Python语言基础知识(一)

文章目录 1、Python内置对象介绍2、标识符与变量3、数据类型—数字4、数据类型—字符串与字节串5、数据类型—列表、元组、字典、集合6、运算符和表达式7、运算符和表达式—算术运算符8、运算符和表达式—关系运算符9.1、运算符和表达式— 成员测试运算符in9.2、运算符和表达式…...

Xilinx FPGA平台DDR3设计详解(三):DDR3 介绍

本文介绍一下常用的存储芯片DDR3&#xff0c;包括DDR3的芯片型号识别、DDR3芯片命名、DDR3的基本结构等知识&#xff0c;为后续掌握FPGA DDR3的读写控制打下坚实基础。 一、DDR3芯片型​号 电路板上的镁光DDR3芯片上没有具体的型号名。 ​如果想知道具体的DDR3芯片型号&#…...

字典的遍历

字典不是有序的集合&#xff0c;就不能通过index来遍历了&#xff0c;那如何遍历字典呢? 方法一:直接用字典 for key in a_dict: print a_dict[key] 通过这样的结构可以的。 d {"liming" : 98, "wangli":95, "mali":90, "liping&q…...

Linux环境下的MySQL安装

文章目录 前提说明1.卸载内置环境2.检查系统安装包3.卸载这些默认安装包4.获取MySQL官方yum源5.安装MySQLyum源&#xff0c;对比前后yum源6.查看yum源是否生效7.安装MySQL服务8.查看相对应的配置文件9.启动服务10.查看启动服务11.登录方法一12.登录方法二13.登录方法三14.设置开…...

梦想与魔法:编程之路的挑战与荣耀

在年少轻狂的岁月里&#xff0c;我们都有过一些不切实际的梦想&#xff0c;渴望成为某种神奇的存在。我的梦想是成为一名神奇的码农&#xff0c;用键盘编织魔法&#xff0c;创造出炫酷的虚拟世界。然而&#xff0c;现实是残酷的&#xff0c;当我刚入门计算机领域时&#xff0c;…...

qt 5.15.2 主窗体菜单工具栏树控件功能

qt 5.15.2 主窗体菜单工具栏树控件功能 显示主窗体效果&#xff1a; mainwindow.h文件内容&#xff1a; #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow> #include <QFileDialog> #include <QString> #include <QMessageBox>#inc…...

Day15——File类与IO流

1.java.io.File类的使用 1.1 File类的理解 File 类及本章下的各种流&#xff0c;都定义在 java.io 包下。一个 File 对象代表硬盘或网络中可能存在的一个文件或者文件目录&#xff08;俗称文件夹&#xff09;&#xff0c;与平台无关。&#xff08;体会万事万物皆对象&#xf…...

【Qt】QLineEdit显示输入十六进制,位数不足时按照规则填充显示及每两个字符以空格填充

问题 在实际开发中&#xff0c;有时候需要对输入进行限制&#xff0c;一是更加合理&#xff0c;二是防止出现误操作。 比如&#xff1a; 使用Qt进行应用程序开发时&#xff0c;对单行编辑框QLineEdit控件&#xff0c;设置只可输入十六进制。 限制输入的方式常用且经典的是使用…...

GPT 中文提示词技巧:参照 OpenAI 官方教程

前言 搜了半天什么 prompt engineering 的课&#xff0c;最后会发现 gpt 官方其实是有 prompt 教程的。因此本文主要是学习这篇教程。 概述 - OpenAI API 部分案例是参考&#xff1a;根据吴恩达老师教程总结出中文版prompt教程_哔哩哔哩_bilibili up主的内容。 一、尽可能清…...

原生微信小程序将字符串生成二维码图片

weapp-qrcode.js再最后 inde.ts中的内容 // pages/qrCode/index.ts // 引入weapp-qrcode.js文件 var QRCode require(../../utils/weapp-qrcode) Page({/*** 页面的初始数据*/data: {orderNo:"",imagePath:},/*** 生命周期函数--监听页面加载*/onLoad(options:any)…...

深入理解HTTPS加密协议

在现代网络环境中&#xff0c;数据安全和隐私保护至关重要。HTTPS&#xff08;全称为HyperText Transfer Protocol Secure&#xff09;是一种用于保障互联网通信安全的加密协议&#xff0c;它通过在HTTP协议的基础上添加SSL/TLS层来实现对数据的加密传输。本文将详细介绍HTTPS的…...

路径规划之PRM算法

系列文章目录 路径规划之Dijkstra算法 路径规划之Best-First Search算法 路径规划之A *算法 路径规划之D *算法 路径规划之PRM算法 路径规划之PRM算法 系列文章目录前言一、前期准备1.栅格地图2.采样3.路标 二、PRM算法1.起源2.流程3. 优缺点4. 实际效果 前言 之前提到的几种…...

深入理解数据在内存中是如何存储的,位移操作符如何使用(能看懂文字就能明白系列)文章超长,慢慢品尝

系列文章目录 C语言笔记专栏 能看懂文字就能明白系列 &#x1f31f; 个人主页&#xff1a;古德猫宁- &#x1f308; 信念如阳光&#xff0c;照亮前行的每一步 文章目录 系列文章目录&#x1f308; *信念如阳光&#xff0c;照亮前行的每一步* 前言引子一、2进制和进制转化为什么…...

ArcGIS提示当前许可不支持影像服务器

1、问题&#xff1a; 在用ArcGIS上处理影像栅格数据时&#xff08;比如栅格数据集裁剪、镶嵌数据集构建镶嵌线等&#xff09;经常会出现。 无法启动配置 RasterComander.ImageServer <详信息 在计算机XXXXX上创建服务器对象实例失败 当前许可不支持影像服务器。 ArcGIS提示当…...

Android P 9.0 增加以太网静态IP功能

效果图 一、Settings添加以太网的配置&#xff1a; 1、vendor\mediatek\proprietary\packages\apps\MtkSettings\res\xml\network_and_internet.xml <com.android.settingslib.RestrictedPreferenceandroid:key"ethernet_settings"android:title"string/et…...

Android12之MediaCodec硬编解码调试手段(四十九)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒体系统工程师系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只…...

2.Ansible的copy模块,我最常用的模块

1. 简述 先从我自身的情况来说&#xff0c;我不是运维人员&#xff0c;并且对linux操作也不是特别熟悉&#xff0c;所以工作中我使用ansible基本就是在平常的自动化部署中&#xff0c;而使用最多的模块就是copy模块。我使用copy模块也主要是来替换生产环境的配置文件。所以&am…...

python程序将部分文件复制到指定目录

geotools-28.2中的lib一共有264个jar包&#xff0c;但我只想将部分100个左右jar包引导我的环境中&#xff0c;那个就需要从目录中找出想要的那100个jar&#xff0c;手动挑选太费时间&#xff0c;我简单的写了个小脚本来实现。 我将想要的jar文件名和路径存放到txt中&#xff0…...

5分钟教你利用服务器,打造1个 7*24H直播的直播间

最近在折腾无人直播。觉得还挺有意思&#xff0c;接下来就分享一下如何实现。实现后就可以给一些主流的平台直播间不间断推流&#xff0c;达到无人直播的效果。 前提&#xff1a;拥有一台服务器。最好流量是1T或者以上。直播对流量要求比较高&#xff0c;视频码率越大&#xff…...

Python|GIF 解析与构建(5):手搓截屏和帧率控制

目录 Python&#xff5c;GIF 解析与构建&#xff08;5&#xff09;&#xff1a;手搓截屏和帧率控制 一、引言 二、技术实现&#xff1a;手搓截屏模块 2.1 核心原理 2.2 代码解析&#xff1a;ScreenshotData类 2.2.1 截图函数&#xff1a;capture_screen 三、技术实现&…...

Chapter03-Authentication vulnerabilities

文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

stm32G473的flash模式是单bank还是双bank?

今天突然有人stm32G473的flash模式是单bank还是双bank&#xff1f;由于时间太久&#xff0c;我真忘记了。搜搜发现&#xff0c;还真有人和我一样。见下面的链接&#xff1a;https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...

srs linux

下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935&#xff0c;SRS管理页面端口是8080&#xff0c;可…...

解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错

出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上&#xff0c;所以报错&#xff0c;到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本&#xff0c;cu、torch、cp 的版本一定要对…...

Linux-07 ubuntu 的 chrome 启动不了

文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了&#xff0c;报错如下四、启动不了&#xff0c;解决如下 总结 问题原因 在应用中可以看到chrome&#xff0c;但是打不开(说明&#xff1a;原来的ubuntu系统出问题了&#xff0c;这个是备用的硬盘&a…...

Java入门学习详细版(一)

大家好&#xff0c;Java 学习是一个系统学习的过程&#xff0c;核心原则就是“理论 实践 坚持”&#xff0c;并且需循序渐进&#xff0c;不可过于着急&#xff0c;本篇文章推出的这份详细入门学习资料将带大家从零基础开始&#xff0c;逐步掌握 Java 的核心概念和编程技能。 …...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列&#xff0c;以便知晓哪些列包含有价值的数据&#xff0c;…...

以光量子为例,详解量子获取方式

光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学&#xff08;silicon photonics&#xff09;的光波导&#xff08;optical waveguide&#xff09;芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中&#xff0c;光既是波又是粒子。光子本…...