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

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(依赖注入&#xff09…...

1000亿数据、30W级qps如何架构?来一个天花板案例

1000亿级存储、30W级qps系统如何架构?来一个天花板案例 说在前面 在尼恩的(50)读者社群中,经常遇到一个 非常、非常高频的一个架构面试题,类似如下: 千万级数据,如何做系统架构?亿…...

人工智能及其应用(蔡自兴)期末复习

人工智能及其应用(蔡自兴)期末复习 相关资料: 人工智能期末复习 人工智能复习题 人工智能模拟卷 人工智能期末练习题 1 ⭐️绪论 人工智能:人工智能就是用人工的方法在机器(计算机)上实现的智能&#xff0…...

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 反射的概述: **专业的解释(了解一下):**是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意属性和方法&#xff…...

应用和迭代(名词解释)

应用和迭代是什么意思 应用: ● 一个完整的前端应用,一般用应用脚手架创建,包含路由,页面,状态等 ● 一个应用对应一个代码仓库 ● 应用的分组(业务中心,数据中台等)只用于逻辑分类&…...

HTMLCollection 和 NodeList 区别

Node 和 Element DOM 是一棵树&#xff0c;所有节点都是 NodeNode 是 Element 的基类Element 是其他 HTML 元素的基类&#xff0c;如 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()是一个系统调用&#xff0c;不是一个函数。详细信息可以&#xff0c;man…...

结构体内存对齐

结构体相信大家已经了解过了&#xff0c;现在我们深入讨论一个问题&#xff0c;计算结构体的大小 也是很热门的一个考点&#xff1a;结构体内存对齐 先看看下面结构体的大小 typedef struct Test {char a;char b;char c; }Test; 很容易看出答案为3&#xff0c;结构体的大小位…...

【C语言进阶】指针进阶

今日所做之事勿候明天&#xff0c;自我所做之事勿候他人。 --歌德 目录 指针进阶(更深层次的理解): 一.字符指针 二.指针数组 ​三.数组指针 1.数组指针的定义: 2.&数组名和数组名: 3.数组指针的使用: 四.数组参数&#xff0c;指针参数 1.一维数组传参:…...

java:Class的isPrimitive方法使用

java&#xff1a;Class的isPrimitive方法使用 1 前言 java中Class类的isPrimitive方法&#xff0c;用于检查类型是否为基本类型。java虚拟机创建了int、byte、short、long、float、double、boolean、char这8种基础信息&#xff0c;以及void&#xff0c;一共9种。为这9种类型时…...

TCP 握手过程 三次 四次

蛋老师视频 SYN 同步 ACK 确认 FIN 结束 核心机制是确定哪些请求或响应需要丢弃 SYN、ACK、FIN 通过 1/0 设置开启/关闭 开启SYN后&#xff0c;报文中会随机生成 Sequence序号 用于校验 &#xff08;应用可能发起多个会话&#xff0c;可以区分&#xff09; 服务器的同步序…...

在rocky linux 9.5上在线安装 docker

前面是指南&#xff0c;后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

Frozen-Flask :将 Flask 应用“冻结”为静态文件

Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是&#xff1a;将一个 Flask Web 应用生成成纯静态 HTML 文件&#xff0c;从而可以部署到静态网站托管服务上&#xff0c;如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

Python爬虫(二):爬虫完整流程

爬虫完整流程详解&#xff08;7大核心步骤实战技巧&#xff09; 一、爬虫完整工作流程 以下是爬虫开发的完整流程&#xff0c;我将结合具体技术点和实战经验展开说明&#xff1a; 1. 目标分析与前期准备 网站技术分析&#xff1a; 使用浏览器开发者工具&#xff08;F12&…...

HBuilderX安装(uni-app和小程序开发)

下载HBuilderX 访问官方网站&#xff1a;https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本&#xff1a; Windows版&#xff08;推荐下载标准版&#xff09; Windows系统安装步骤 运行安装程序&#xff1a; 双击下载的.exe安装文件 如果出现安全提示&…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

Android第十三次面试总结(四大 组件基础)

Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成&#xff0c;用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机&#xff1a; ​onCreate()​​ ​调用时机​&#xff1a;Activity 首次创建时调用。​…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek

文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama&#xff08;有网络的电脑&#xff09;2.2.3 安装Ollama&#xff08;无网络的电脑&#xff09;2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...

【Go语言基础【12】】指针:声明、取地址、解引用

文章目录 零、概述&#xff1a;指针 vs. 引用&#xff08;类比其他语言&#xff09;一、指针基础概念二、指针声明与初始化三、指针操作符1. &&#xff1a;取地址&#xff08;拿到内存地址&#xff09;2. *&#xff1a;解引用&#xff08;拿到值&#xff09; 四、空指针&am…...