Springboot Java多线程操作本地文件,加读写锁,阻塞的线程等待运行中的线程执行完再查询并写入
Springboot Java多线程操作本地文件,加读写锁,阻塞的线程等待运行中的线程执行完再查询并写入
- 1、读写锁
- 2、文件锁
- 3、Synchronized和Lock的区别
1、读写锁
在 Spring Boot 中进行多线程操作本地文件并加读写锁可以使用 Java 的 java.nio.file 包中提供的文件操作方法,以及 Java 的 java.util.concurrent 包中提供的读写锁来实现。下面是一个示例代码:
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.locks.ReentrantReadWriteLock;public class FileReadWriteExample {private static ReentrantReadWriteLock lock = new ReentrantReadWriteLock();public static void main(String[] args) {Path path = Paths.get("example.txt");Thread writer = new Thread(() -> {try {lock.writeLock().lock();// 写文件操作Files.writeString(path, "Hello World!");} catch (Exception e) {e.printStackTrace();} finally {lock.writeLock().unlock();}});Thread reader = new Thread(() -> {try {lock.readLock().lock();// 读文件操作String content = Files.readString(path);System.out.println(content);} catch (Exception e) {e.printStackTrace();} finally {lock.readLock().unlock();}});writer.start();try {writer.join();} catch (InterruptedException e) {e.printStackTrace();}reader.start();}
}
在这个示例中,我们使用 ReentrantReadWriteLock 来实现读写锁,确保只有一个线程在执行写操作,而多个线程可以同时执行读操作。在这个示例中,我们首先创建一个 Path 对象来表示要读写的文件,然后创建一个写线程和一个读线程。写线程首先获取写锁,然后执行写操作,最后释放写锁。读线程获取读锁,执行读操作,最后释放读锁。
为了确保读线程在写线程执行完毕后再执行,我们使用 Thread.join() 方法来等待写线程执行完毕。这样,当写线程执行完毕并释放写锁时,读线程才能获取读锁并执行读操作。如果读线程在写线程还未执行完毕时尝试获取读锁,它会被阻塞,直到写线程释放写锁。
2、文件锁
在 Spring Boot 中使用 Java 多线程操作本地文件并加文件锁,阻塞的线程等待运行中的线程执行完再查询并写入可以采用以下步骤:
使用Java的java.nio.channels.FileChannel类获取文件通道。
创建一个文件锁:使用文件通道的lock()方法创建一个文件锁,以确保多线程读写文件时的互斥。
创建一个写线程:使用Java的java.lang.Thread类创建一个写线程,并在该线程中获取文件锁,然后执行写操作。
创建一个读线程:使用Java的java.lang.Thread类创建一个读线程,并在该线程中获取文件锁,然后执行读操作。
在主线程中等待写线程执行完毕:使用Java的java.lang.Thread类的join()方法,在主线程中等待写线程执行完毕。
在主线程中等待读线程执行完毕:使用Java的java.lang.Thread类的join()方法,在主线程中等待读线程执行完毕。
下面是一个示例代码:
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;public class FileReadWriteExample {private static final String FILE_NAME = "example.txt";public static void main(String[] args) {Thread writerThread = new Thread(() -> {try (RandomAccessFile file = new RandomAccessFile(FILE_NAME, "rw");FileChannel channel = file.getChannel();FileLock lock = channel.lock()) {// 执行写操作channel.write("Hello World!".getBytes());} catch (IOException e) {e.printStackTrace();}});Thread readerThread = new Thread(() -> {try (RandomAccessFile file = new RandomAccessFile(FILE_NAME, "r");FileChannel channel = file.getChannel();FileLock lock = channel.lock(0L, Long.MAX_VALUE, true)) {// 执行读操作String content = new String(channel.map(FileChannel.MapMode.READ_ONLY, 0L, channel.size()).array());System.out.println("Content: " + content);} catch (IOException e) {e.printStackTrace();}});// 启动写线程writerThread.start();try {// 等待写线程执行完毕writerThread.join();} catch (InterruptedException e) {e.printStackTrace();}// 启动读线程readerThread.start();try {// 等待读线程执行完毕readerThread.join();} catch (InterruptedException e) {e.printStackTrace();}}
}
在这个示例中,我们使用了 FileChannel 和 FileLock 来创建文件锁,并在写线程和读线程中分别获取文件锁。
在写线程中,我们使用文件通道的 write() 方法来写入数据;在读线程中,我们使用文件通道的 map() 方法来读取数据。
同时,我们还需要在读线程中使用 lock() 方法获取共享锁,这样可以确保读线程在写线程执行完毕后再执行,避免在主线程中,
我们首先启动写线程,然后使用 join() 方法等待写线程执行完毕。接着,我们启动读线程,
并使用 join() 方法等待读线程执行完毕。这样可以确保读线程在写线程执行完毕后才会执行,从而确保读取到的数据是完整的。
需要注意的是,在使用文件锁时,需要根据具体的需求来选择锁类型。在上面的示例中,我们在写线程中使用了独占锁(lock() 方法),在读线程中使用了共享锁(lock(0L, Long.MAX_VALUE, true) 方法)
,这样可以避免写线程和读线程之间的互相干扰。
另外,需要注意文件锁的作用范围。在上面的示例中,我们只是对整个文件加了锁,如果需要对文件中的某一部分加锁,
可以使用 lock(long position, long size, boolean shared) 方法来指定锁的位置和大小。
其中,position 参数表示锁的起始位置,size 参数表示锁的大小,shared 参数表示是否为共享锁。
需要注意的是,在使用这个方法时,需要确保文件通道的当前位置在锁的起始位置上,
否则会抛出 NonWritableChannelException 或 NonReadableChannelException 异常。
可以使用 position() 方法来获取或设置文件通道的当前位置。
总之,在使用 Java 多线程操作本地文件时,加文件锁是一种保证线程安全的有效方式,
可以避免多个线程同时读写同一个文件而导致的数据不一致问题。但是需要注意锁的类型和作用范围,以及加锁的时机和释放锁的时机,以避免出现死锁等问题。
3、Synchronized和Lock的区别
synchronized 和 Lock 都是 Java 中用于实现线程同步的机制,它们的主要作用是确保多个线程对共享资源的访问顺序和互斥性,从而避免数据竞争和并发访问导致的不一致问题。
以下是 synchronized 和 Lock 的主要区别:
1、范围:synchronized 是 Java 内置的关键字,可以用于同步方法和同步代码块,而 Lock 是一个接口,需要通过实现类来使用。
2、锁的类型:synchronized 是隐式锁,即 JVM 自动为我们加锁和释放锁,而 Lock 是显式锁,需要手动加锁和释放锁。
3、性能:在 Java 5 之前,synchronized 的性能比 Lock 要好,但是在 Java 5 之后,Lock 的性能得到了大幅度提升,特别是在高并发的情况下,Lock 的性能优势更加明显。
4、可中断性:synchronized 是不可中断的锁,一旦一个线程进入了一个 synchronized 块,其他线程就必须等待该线程执行完毕并释放锁,才能继续执行。而 Lock 是可中断的锁,即一个线程在等待锁的时候,可以通过调用 lockInterruptibly() 方法来中断等待。
5、条件变量:Lock 提供了条件变量,可以使用 Condition 接口来实现等待/通知模型,而 synchronized 没有提供对应的机制。
6、灵活性:Lock 的灵活性比 synchronized 更高,例如可以选择公平锁或非公平锁,可以设置超时时间等。
总之,虽然 synchronized 和 Lock 都可以用于实现线程同步,但是它们的使用方法和特点有所不同,需要根据具体的需求来选择合适的机制。在 JDK 5 之后,由于 Lock 的性能提升和灵活性,越来越多的开发者使用 Lock 来实现线程同步。
相关文章:
Springboot Java多线程操作本地文件,加读写锁,阻塞的线程等待运行中的线程执行完再查询并写入
Springboot Java多线程操作本地文件,加读写锁,阻塞的线程等待运行中的线程执行完再查询并写入1、读写锁2、文件锁3、Synchronized和Lock的区别1、读写锁 在 Spring Boot 中进行多线程操作本地文件并加读写锁可以使用 Java 的 java.nio.file 包中提供的文…...
WebRTC拥塞控制算法——GCC介绍
网络拥塞是基于IP协议的数据报交换网络中常见的一种网络传输问题,它对网络传输的质量有严重的影响, 网络拥塞是导致网络吞吐降低, 网络丢包等的主要原因之一, 这些问题使得上层应用无法有效的利用网络带宽获得高质量的网络传输效果…...
大数据技术之Maxwell基础知识
大数据技术之Maxwell基础知识 文章目录大数据技术之Maxwell基础知识0、写在前面1、Maxwell 概述1.1 Maxwell 定义1.2 Maxwell 工作原理1.2.1 MySQL 主从复制过程1.2.2 Maxwell 的工作原理1.2.3 MySQL 的 binlog1.3 Maxwell与Cannal对比2. Maxwell 使用2.1 Maxwell 安装部署2.1.…...
元数据管理实践数据血缘
元数据管理实践&数据血缘 什么是元数据?元数据MetaData狭义的解释是用来描述数据的数据,广义的来看,除了业务逻辑直接读写处理的那些业务数据,所有其它用来维持整个系统运转所需的信息/数据都可以叫作元数据。比如…...
SQL的优化【面试工作】
SQL的优化 最近看到群友在讨论这块的优化,感觉不管工作和面试,都是用上的,记录下吧!(不然又记不住) 优化点: 处理和优化复杂的 SQL 查询可以有以下几个方向: 1.优化查询语句本身 首先,可以优化 SQL 查询语句本身,尽量让其更加简洁、高效。 …...
Kotlin 40. Dependency Injection 依赖注入以及Hilt在Kotlin中的使用,系列3:Hilt 注释介绍及使用案例
一起来学Kotlin:概念:27. Dependency Injection 依赖注入以及Hilt在Kotlin中的使用,系列3:Hilt 注释介绍及使用案例 此系列博客中,我们将主要介绍: Dependency Injection(依赖注入)…...
1000亿数据、30W级qps如何架构?来一个天花板案例
1000亿级存储、30W级qps系统如何架构?来一个天花板案例 说在前面 在尼恩的(50)读者社群中,经常遇到一个 非常、非常高频的一个架构面试题,类似如下: 千万级数据,如何做系统架构?亿…...
人工智能及其应用(蔡自兴)期末复习
人工智能及其应用(蔡自兴)期末复习 相关资料: 人工智能期末复习 人工智能复习题 人工智能模拟卷 人工智能期末练习题 1 ⭐️绪论 人工智能:人工智能就是用人工的方法在机器(计算机)上实现的智能࿰…...
openpnp - configure - 矫正里程碑
文章目录openpnp - configure - 矫正里程碑概述备注ENDopenpnp - configure - 矫正里程碑 概述 进入矫正里程碑了 查找问题 现在第一个问题是X轴的齿隙矫正 根据提示, 将顶部相机移动到主基准点上, 选择容差(就选用默认的0.025), 开始矫正. 正好开机后, 使能了视觉原点归零. …...
JavaScript高级程序设计读书分享之8章——8.2创建对象
JavaScript高级程序设计(第4版)读书分享笔记记录 适用于刚入门前端的同志 创建Object的实例 let person new Object(); person.name "Nicholas"; person.age 29; person.job "Software Engineer"; person.sayName function() { console.log(this…...
关于Could not build wheels for opencv-python-headless, which is...报错的解决方案
在通过最新版pip在线安装package:opencv-python-headless的时候,会产生报错信息,主要为 ERROR: Failed building wheel for opencv-python-headless ERROR: Could not build wheels for opencv-python-headless, which is required to insta…...
【K3s】第1篇 K3s入门级介绍及架构详解
1、什么是 K3s? K3s 是一个轻量级的 Kubernetes 发行版,它针对边缘计算、物联网等场景进行了高度优化。K3s 有以下增强功能: 打包为单个二进制文件。使用基于 sqlite3 的轻量级存储后端作为默认存储机制。同时支持使用 etcd3、MySQL 和 PostgreSQL 作…...
Java学习--反射
1. 反射 1.1 反射的概述: **专业的解释(了解一下):**是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意属性和方法ÿ…...
应用和迭代(名词解释)
应用和迭代是什么意思 应用: ● 一个完整的前端应用,一般用应用脚手架创建,包含路由,页面,状态等 ● 一个应用对应一个代码仓库 ● 应用的分组(业务中心,数据中台等)只用于逻辑分类&…...
HTMLCollection 和 NodeList 区别
Node 和 Element DOM 是一棵树,所有节点都是 NodeNode 是 Element 的基类Element 是其他 HTML 元素的基类,如 HTMLDivElement HTMLCollection 和 NodeList HTMLCollection 是 Element 的集合NodeList 是 Node 的集合 <body><p id"p1&qu…...
fork()出来一个进程,这个进程的父进程是从哪来的?
基本概念fork() creates a new process by duplicating the calling process. The new process is referred to as the child process. The calling process is referred to as the parent process.fork()是一个系统调用,不是一个函数。详细信息可以,man…...
结构体内存对齐
结构体相信大家已经了解过了,现在我们深入讨论一个问题,计算结构体的大小 也是很热门的一个考点:结构体内存对齐 先看看下面结构体的大小 typedef struct Test {char a;char b;char c; }Test; 很容易看出答案为3,结构体的大小位…...
【C语言进阶】指针进阶
今日所做之事勿候明天,自我所做之事勿候他人。 --歌德 目录 指针进阶(更深层次的理解): 一.字符指针 二.指针数组 三.数组指针 1.数组指针的定义: 2.&数组名和数组名: 3.数组指针的使用: 四.数组参数,指针参数 1.一维数组传参:…...
java:Class的isPrimitive方法使用
java:Class的isPrimitive方法使用 1 前言 java中Class类的isPrimitive方法,用于检查类型是否为基本类型。java虚拟机创建了int、byte、short、long、float、double、boolean、char这8种基础信息,以及void,一共9种。为这9种类型时…...
TCP 握手过程 三次 四次
蛋老师视频 SYN 同步 ACK 确认 FIN 结束 核心机制是确定哪些请求或响应需要丢弃 SYN、ACK、FIN 通过 1/0 设置开启/关闭 开启SYN后,报文中会随机生成 Sequence序号 用于校验 (应用可能发起多个会话,可以区分) 服务器的同步序…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...
《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...
uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
[论文阅读]TrustRAG: Enhancing Robustness and Trustworthiness in RAG
TrustRAG: Enhancing Robustness and Trustworthiness in RAG [2501.00879] TrustRAG: Enhancing Robustness and Trustworthiness in Retrieval-Augmented Generation 代码:HuichiZhou/TrustRAG: Code for "TrustRAG: Enhancing Robustness and Trustworthin…...
水泥厂自动化升级利器:Devicenet转Modbus rtu协议转换网关
在水泥厂的生产流程中,工业自动化网关起着至关重要的作用,尤其是JH-DVN-RTU疆鸿智能Devicenet转Modbus rtu协议转换网关,为水泥厂实现高效生产与精准控制提供了有力支持。 水泥厂设备众多,其中不少设备采用Devicenet协议。Devicen…...
Pydantic + Function Calling的结合
1、Pydantic Pydantic 是一个 Python 库,用于数据验证和设置管理,通过 Python 类型注解强制执行数据类型。它广泛用于 API 开发(如 FastAPI)、配置管理和数据解析,核心功能包括: 数据验证:通过…...
解析“道作为序位生成器”的核心原理
解析“道作为序位生成器”的核心原理 以下完整展开道函数的零点调控机制,重点解析"道作为序位生成器"的核心原理与实现框架: 一、道函数的零点调控机制 1. 道作为序位生成器 道在认知坐标系$(x_{\text{物}}, y_{\text{意}}, z_{\text{文}}…...
