JAVA 文件锁 FileLock

作者: jijs | 来源:发表于2017-10-29 16:07 被阅读612次

    概述

    FileLock是java 1.4 版本后出现的一个类,它可以通过对一个可写文件(w)加锁,保证同时只有一个进程可以拿到文件的锁,这个进程从而可以对文件做访问;而其它拿不到锁的进程要么选择被挂起等待,要么选择去做一些其它的事情, 这样的机制保证了众进程可以顺序访问该文件。也可以看出,能够利用文件锁的这种性质,在一些场景下,虽然我们不需要操作某个文件, 但也可以通过 FileLock 来进行并发控制,保证进程的顺序执行,避免数据错误。

    共享锁、独占锁

    • 共享锁:允许多个线程进行文件的读取操作
    • 独占锁: 只允许一个线程进行文件的读/写操作

    获得 FileLock

    通过 NIO 的 API 首先获取文件的 FileChannel ,然后可以通过 FileChannel 以下4中方式获取FileLock。

    1. 通过lock() 获取 FileLock,获取文件的独占锁

    public final FileLock lock() throws IOException {
        return lock(0L, Long.MAX_VALUE, false);
    }
    

    默认锁定整个文件,并设置为独占锁。

    2. 通过改方法可以锁定文件的部分数据,并支持设置共享锁。

    public FileLock lock(long position, long size, boolean shared) throws IOException{
      ......
    }
    
    • position:锁定文件中的开始位置
    • size: 锁定文件中的内容长度
    • shared: 是否使用共享锁。true为共享锁定;false为独占锁定。

    一些不支持共享锁的操作系统,将自动将共享锁改成排它锁。可以通过调用isShared()方法来检测获得的是什么类型的锁。

    3. 试图获取文件独占锁

    public final FileLock tryLock() throws IOException {
        return tryLock(0L, Long.MAX_VALUE, false);
    }
    

    如果获取不到锁,则返回null。而不阻塞当前线程,等待获取锁。

    4. 通过改方法可以尝试获得文件的部分数据的锁,并支持设置共享锁。

    public abstract FileLock tryLock(long position, long size, boolean shared) throws IOException{
        ......
    }
    

    参数同上2。
    如果获取不到锁,则返回null。

    使用场景

    1. 如果多个应用部署到同一台机器上,并且同时操作同一份数据(数据库中或文件中的数据),可以使用FileLock充当分布式锁。

    示例

    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.nio.channels.FileChannel;
    import java.nio.channels.FileLock;
    
    public class FileLockTest {  
      
        public static void main(String[] args){  
            FileLock lock = null;  
            try (FileChannel channel = new FileOutputStream("d:\\file.lock",true).getChannel()){  
                lock = channel.lock();//无参lock()为独占锁
                //lock = channel.lock(0L, channel.size(), true);    //共享锁
                //其它逻辑
                ......
            } catch (FileNotFoundException e) {  
                e.printStackTrace();  
            } catch (IOException e) {  
                e.printStackTrace();  
            } finally {  
                if (lock != null) {  
                    try {  
                        lock.release();  
                        lock = null;  
                    } catch (IOException e) {  
                        e.printStackTrace();  
                    }  
                }  
            }  
        }  
    }  
    
    1. 对于一个只读文件通过任意方式加锁时会报NonWritableChannelException异常
    2. 无参lock()默认为独占锁,不会报NonReadableChannelException异常,因为独占就是为了写
    3. 有参lock()为共享锁,所谓的共享也只能读共享,写是独占的,共享锁控制的代码只能是读操作,当有写冲突时会报NonWritableChannelException异常

    想了解更多精彩内容请关注我的公众号

    相关文章

      网友评论

      • 独居的绵羊:楼上说的我也觉得有点疑惑,多个应用程序访问一个文件不是进程占用了?只有同一个程序才能用文件锁吧
        jijs:@独居的绵羊 filelock是进程之间的锁,不是线程之间的锁
        jijs:@独居的绵羊 同一个程序,就没必要用文件锁了,用Lock或synchronous岂不更好?
      • c22a3de3691f:哥, 你对java线程和进程的概念都没搞清楚, 误人子弟吧

      本文标题:JAVA 文件锁 FileLock

      本文链接:https://www.haomeiwen.com/subject/poeypxtx.html