【死磕NIO】— 跨进程文件锁:FileLock

大家好,我是大明哥,一个专注于【死磕 Java】系列创作的程序员。
【死磕 Java 】系列为作者「chenssy」 倾情打造的 Java 系列文章,深入分析 Java 相关技术核心原理及源码
死磕 Java :https://www.cmsblogs.com/group/1420041599311810560

【死磕NIO】— 跨进程文件锁:FileLock

上篇文章(【死磕 NIO】— 深入分析Channel和FileChannel)已经详细介绍了 FileChannel的核心原理及相关API,了解了FileChannel是用来读写和映射一个系统文件的 Channel,其实他还有很牛逼的功能就是:跨进程文件锁。

说一个场景有多个进程同时操作某一个文件,并行往文件中写数据,请问如何保证写入文件的内容是正确的?可能有小伙伴说加分布式锁,可以解决问题,但是有点儿重了。

有没有更加轻量级的方案呢? 多进程文件锁:FileLock

FileLock

FileLock是文件锁,它能保证同一时间只有一个进程(程序)能够修改它,或者都只可以读,这样就解决了多进程间的同步文件,保证了安全性。但是需要注意的是,它进程级别的,不是线程级别的,他可以解决多个进程并发访问同一个文件的问题,但是它不适用于控制同一个进程中多个线程对一个文件的访问。这也是为什么它叫做 多进程文件锁,而不是 多线程文件锁

FileLock一般都是从FileChannel 中获取,FileChannel 提供了三个方法用以获取 FileLock。

public abstract FileLock lock(long position, long size, boolean shared) throws IOException; public final FileLock lock() throws IOException; public abstract FileLock tryLock(long position, long size, boolean shared) throws IOException; public final FileLock tryLock() throws IOException;

lock() 是阻塞式的,它要阻塞进程直到锁可以获得,或调用lock()的线程中断,或调用lock()的通道关闭。

tryLock()是非阻塞式的,它设法获取锁,但如果不能获得,例如因为其他一些进程已经持有相同的锁,而且不共享时,它将直接从方法调用返回。

lock()和tryLock()方法有三个参数,如下:

position:锁定文件中的开始位置

size:锁定文件中的内容长度

shared:是否使用共享锁。true为共享锁;false为独占锁。

共享锁和独占锁的区别,大明哥就不解释了。

示例

不使用文件锁来读写文件

首先我们不使用文件锁来进行多进程间文件读写,进程1往文件中写数据,进程2读取文件的大小。

进程1

RandomAccessFile randomAccessFile = new RandomAccessFile("/Users/chenssy/Downloads/filelock.txt","rw"); FileChannel fileChannel = randomAccessFile.getChannel(); // 这里是独占锁 //FileLock fileLock = fileChannel.lock(); System.out.println("进程 1 开始写内容:" + LocalTime.now()); for(int i = 1 ; i <= 10 ; i++) { randomAccessFile.writeChars("chenssy_" + i); // 等待两秒 TimeUnit.SECONDS.sleep(2); } System.out.println("进程 1 完成写内容:" + LocalTime.now()); // 完成后要释放掉锁 //fileLock.release(); fileChannel.close(); randomAccessFile.close();

进程2

RandomAccessFile randomAccessFile = new RandomAccessFile("/Users/chenssy/Downloads/filelock.txt","rw"); FileChannel fileChannel = randomAccessFile.getChannel(); // 这里是独占锁 //FileLock fileLock = fileChannel.lock(); System.out.println("开始读文件的时间:" + LocalTime.now()); for(int i = 0 ; i < 10 ; i++) { // 这里直接读文件的大小 System.out.println("文件大小为:" + randomAccessFile.length()); // 这里等待 1 秒 TimeUnit.SECONDS.sleep(1); } System.out.println("结束读文件的时间:" + LocalTime.now()); // 完成后要释放掉锁 //fileLock.release(); fileChannel.close(); randomAccessFile.close();

运行结果

进程1

【死磕NIO】— 跨进程文件锁:FileLock

进程2

【死磕NIO】— 跨进程文件锁:FileLock

从这个结果可以非常清晰看到,进程1和进程2是同时执行的。进程1一边往文件中写,进程2是一边在读的

使用文件锁读写文件

这里我们使用文件锁来进行多进程间文件读写,依然使用上面的程序,只需要将对应的注释放开即可。执行结果

进程1

【死磕NIO】— 跨进程文件锁:FileLock

进程2

【死磕NIO】— 跨进程文件锁:FileLock

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzzjyp.html