首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐
2025年5月14日 星期三 10:26pm

聊一聊Java中的文件锁

  • 25-03-02 14:22
  • 4244
  • 11143
blog.csdn.net

点击上方“朱小厮的博客”,选择“设为星标”

后台回复”加群“获取公众号专属群聊入口

1. 概览

当读写文件时,需要确保有适当的文件锁定机制,来保证基于并发I/O应用程序的数据完整性。

「本教程中, 我们将介绍使用 Java NIO 库实现这一点的各种方法。」

2. 文件锁简介

「一般来说,有两种锁」:

  • 独占锁——也称为写锁

  • 共享锁——也称为读锁

简单地说,在写操作完成时,独占锁防止所有其他操作(包括读操作)。

相反,共享锁允许多个进程同时读取。读锁的目的是防止另一个进程获取写锁。通常,处于一致状态的文件确实应该被任何进程读取。

在下一节中,我们将看到Java如何处理这些类型的锁。

3. Java中的文件锁

Java NIO库支持在操作系统级别锁定文件。FileChannel 中的lock() 和*tryLock()*方法就是为了这个而存在。

我们可以通过 FileInputStream, FileOutputStream,RandomAccessFile 来获取FileChannel,三者均可通过 getChannel() 方法返回 FileChannel对象.

或者, 我们可以直接通过静态方法 open 来创建 FileChannel  :

  1. try (FileChannel channel = FileChannel.open(path, openOptions)) {
  2. // write to the channel
  3. }

接下来,我们将回顾在Java中获取独占锁和共享锁的不同方式。要了解有关文件通道的更多信息,请查看[Guide to Java FileChanne 教程。

4. 独占锁

正如我们已经了解到的,在写入文件时,「我们可以使用独占锁」防止其他进程读取或写入文件。

我们通过调用 FileChannel 类上的 lock() 或 tryLock()) 来获得独占锁。我们还可以使用它们的重载方法:

  • lock(long position, long size, boolean shared)

  • tryLock(long position, long size, boolean shared)

在这些情况下,shared参数必须设置为false。

要获得独占锁,必须使用可写的文件通道。我们可以通过 FileOutputStream 或 RandomAccessFile 的 getChannel() 方法创建它。或者,如前所述,我们可以使用 FileChannel 类的静态方法:open。我们只需要将第二个参数设置为StandardOpenOption.APPEND :

  1. try (FileChannel channel = FileChannel.open(path, StandardOpenOption.APPEND)) {
  2. // write to channel
  3. }

4.1. 使用 FileOutputStream 的独占锁

从 FileOutputStream 创建的 FileChannel 是可写的。因此,我们可以获得一个独占锁:

  1. try (FileOutputStream fileOutputStream = new FileOutputStream("/tmp/testfile.txt");
  2. FileChannel channel = fileOutputStream.getChannel();
  3. FileLock lock = channel.lock()) {
  4. // write to the channel
  5. }

在这里,channel.lock() 要么阻塞直到获得一个锁,要么抛出一个异常。例如,如果指定的区域已锁定,则会引发OverlappingFileLockException。有关可能的异常的完整列表,请参见Javadoc。我们还可以使用 channel.tryLock() 执行非阻塞锁。如果由于另一个程序持有一个重叠的锁而无法获取锁,则返回null。如果由于任何其他原因未能执行此操作,则会引发相应的异常。

4.2. 使用 RandomAccessFile 的独占锁

使用 RandomAccessFile,我们需要设置 [constructor](https://docs.oracle.com/javase/8/docs/api/java/io/RandomAccessFile.html#RandomAccessFile(java.io.File, java.lang.String)) 方法的第二个参数。

在这里,我们将使用读写权限打开文件:

  1. try (RandomAccessFile file = new RandomAccessFile("/tmp/testfile.txt", "rw");
  2. FileChannel channel = file.getChannel();
  3. FileLock lock = channel.lock()) {
  4. // write to the channel
  5. }

如果我们以只读模式打开文件,并尝试向其通道进行写入操作,将会抛出 NonWritableChannelException 异常。

4.3.独占锁依赖于可读的 FileChannel

如前所述,独占锁需要一个可写通道。因此,我们无法通过从 FileInputStream 创建的 FileChannel 获得独占锁:

  1. Path path = Files.createTempFile("foo","txt");
  2. Logger log = LoggerFactory.getLogger(this.getClass());
  3. try (FileInputStream fis = new FileInputStream(path.toFile());
  4. FileLock lock = fis.getChannel().lock()) {
  5. // unreachable code
  6. } catch (NonWritableChannelException e) {
  7. // handle exception
  8. }

在上面的例子中,lock() 方法将抛出一个 nonwriteablechannelexception 。实际上,这是因为我们正在对一个创建只读通道的 FileInputStream 调用 getChannel。这个例子只是为了证明我们不能写到一个不可写的通道。事实上,我们不会捕捉并重新抛出异常。

5.  共享锁

记住,共享锁也称为读 锁。因此,要获得读锁,我们必须使用可读的文件通道。

这样的 FileChannel 可以通过调用 FileInputStream 或 RandomAccessFile 上的 getChannel() 方法获得。同样,另一个选项是使用 FileChannel 类的静态 open 方法。在这种情况下,我们将第二个参数设置为 StandardOpenOption.READ 。

  1. try (FileChannel channel = FileChannel.open(path, StandardOpenOption.READ);
  2. FileLock lock = channel.lock(0, Long.MAX_VALUE, true)) {
  3. // read from the channel
  4. }

这里要注意的一点是,我们选择通过调用 lock(0, Long.MAX_VALUE, true) 来锁定整个文件。通过将前两个参数更改为不同的值,我们还可以只锁定文件的特定区域。对于共享锁,第三个参数必须设置为true。

为了简单起见,我们将在下面的所有示例中锁定整个文件,但请记住,我们始终可以锁定文件的特定区域。

5.1. 使用 FileInputStream 中的共享锁

从 FileInputStream 获得的 FileChannel 是可读的。因此,我们可以获得一个共享锁:

  1. try (FileInputStream fileInputStream = new FileInputStream("/tmp/testfile.txt");
  2. FileChannel channel = fileInputStream.getChannel();
  3. FileLock lock = channel.lock(0, Long.MAX_VALUE, true)) {
  4. // read from the channel
  5. }

在上面的代码片段中,将成功调用通道上的 lock() 。这是因为共享锁只要求通道是可读的就行。

5.2. 使用 RandomAccessFile中的共享锁

这次,我们只需要使用 ''读" 权限打开文件即可:

  1. try (RandomAccessFile file = new RandomAccessFile("/tmp/testfile.txt", "r");
  2. FileChannel channel = file.getChannel();
  3. FileLock lock = channel.lock(0, Long.MAX_VALUE, true)) {
  4. // read from the channel
  5. }

在本例中,我们创建了一个具有读取权限的RandomAccessFile对象,然后从中创建一个可读通道,从而创建一个共享锁。

5.3. 共享锁依赖于可读的 FileChannel

因此,我们无法通过从 FileOutputStream 创建的 FileChannel 获取共享锁:

  1. Path path = Files.createTempFile("foo","txt");
  2. try (FileOutputStream fis = new FileOutputStream(path.toFile());
  3. FileLock lock = fis.getChannel().lock(0, Long.MAX_VALUE, true)) {
  4. // unreachable code
  5. } catch (NonWritableChannelException e) {
  6. // handle exception
  7. }

在本例中,调用 lock() 尝试获取从 FileOutputStream 创建的通道上的共享锁。这样的通道是只写的。它不能满足通道必须可读的需要。这将触发一个NonWritableChannelException。

同样,这段代码只是为了证明我们不能从一个不可读的通道中读取。

6. 思考

实际上,使用文件锁是困难的;锁定机制是不可移植的。我们需要考虑到这一点来设计锁定逻辑。

在POSIX系统中,锁是建议性的。读取或写入给定文件的不同进程必须就锁定协议达成一致。这将确保文件的完整性。操作系统本身不会强制任何锁定。

在Windows上,除非允许共享,否则锁将是独占的。讨论操作系统特定机制的优点或缺点超出了本文的讨论范围。然而,在实现锁定机制时,了解这些细微差别很重要。

7. 总结

在本教程中,我们回顾了在Java中获取文件锁的几种不同选项。

首先,我们首先了解两种主要的锁定机制,以及Java NIO库如何促进锁定文件。然后,我们浏览了一系列简单的示例,这些示例显示我们可以在应用程序中获得独占和共享锁。我们还研究了使用文件锁时可能遇到的典型异常类型。 

想知道更多?扫描下面的二维码关注我

后台回复”加群“获取公众号专属群聊入口

字节跳动2020春季实习生招聘及校招全职补录全面启动!

【精彩推荐】

  • 咱们从头到尾说一次Java垃圾回收

  • Netty、Kafka中的零拷贝技术到底有多牛?

  • go为什么这么快?

  • 面试前,我们要复习多少Redis知识?

  • 《深入理解Java虚拟机》第2版挖的坑终于在第3版中被R大填平了

  • Redis性能问题分析

  • 浅谈CAP和Paxos共识算法

朕已阅 

文章已被收录至官方知识档案
Java技能树NIO文件锁148947 人正在系统学习中
注:本文转载自blog.csdn.net的朱小厮的文章"https://blog.csdn.net/u013256816/article/details/104832237"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2024 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top