java 文件锁[通俗易懂]

java 文件锁[通俗易懂]今天在分析HDFS数据节点的源码时,了解到在数据节点的文件结构中,当数据节点运行时,${dfs.data.dir}下会有一个名为”in_use.lock”的文件,该文件就是文件锁。文件加锁是JDK1.4引入的一种机制,它允许我们同步访问某个作为共享资源的文件。竞争同一文件的两个线程可能在不同的Java虚拟机上,或者一个是Java线程,另一个是操作系统中的某个本地线程。文件锁对其他的操作系

大家好,又见面了,我是你们的朋友全栈君。

今天在分析HDFS数据节点的源码时,了解到在数据节点的文件结构中,当数据节点运行时,${dfs.data.dir}下会有一个名为”in_use.lock”的文件,该文件就是文件锁。

文件加锁是 JDK1.4 引入的一种机制,它允许我们同步访问某个作为共享资源的文件。竞争同一文件的两个线程可能在不同的 Java 虚拟机上,或者一个是 Java 线程,另一个是操作系统中的某个本地线程。文件锁对其他的操作系统进程是可见的,因为 Java 的文件加锁直接映射到了本地操作系统的加锁工具(通过文件进行加锁)。

在javaNIO中提供了文件锁的功能,这样当一个线程获取文件锁后,才可以操作文件,其他线程是无法操作文件的,要想进行文件锁定的操作,则要使用FileLock类完成,此类的对象需要依靠FileChannel进行实例化。

java文件锁要么独占,要么共享。
共享锁:允许多个线程对文件进行读操作。
独占锁:只允许一个线程进行文件的读写操作

Trylock 与 lock 方法
tryLock(position,size,isShare); 第三个参数为 true 时为共享锁
tryLock() 是非阻塞式的,它设法获取锁,但如果不能获得,例如因为其他一些进程已经持有相同的锁,而且不共享时,抛出文件重叠锁异常【OverlappingFileLockException】。

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

OverlappingFileLockException
单个 Java 虚拟机在某个特定文件上所保持的锁定、不同 jvm 或者不同操作系统获取同一文件锁时,先拿到的获得锁,后获取的抛出文件重叠锁异常【OverlappingFileLockException】。以上是 windows 才会出现如此现象,如果是linux会抛出异常:【java.io.IOException: Permission denied 】

测试代码如下:

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.OverlappingFileLockException;


public class StorageDirectory { 
   
    public static final String STORAGE_FILE_LOCK = "in_use.lock" ;
    File root ; //root directory 
    java.nio.channels.FileLock lock ; //storage lock
    /** * Lock storage to provide exclusive access. * * <p> if locking is supported we guarantee exculsive access to the * storage directory . Otherwise, no guarantee is given * * @throws Exception if locking file */
    public StorageDirectory(File dir){
        this.root = dir ;
    }
    public void lock() throws Exception{
        this.lock = tryLock() ;
        if(lock == null){
            String msg = "Cannot lock storage" + this.root + ". The directory is already locked." ;
            System.err.println(msg) ;
            throw new IOException(msg) ;
        }
    }

    public void unlock() throws IOException{
        if(this.lock == null)
            return ;
        this.lock.release() ;
        lock.channel().close() ;
        lock = null ;
    }
    /** * Attempts to acquire an exclusive lock on the storage * @return A lock object representing the newly-acquired lock or null if * storage is already lockd . * @throws IOException */
    java.nio.channels.FileLock tryLock() throws IOException{
        boolean deletionHookAdded = false ;
        File lockF = new File(root,STORAGE_FILE_LOCK) ;

        //如果没有文件
        if(!lockF.exists()){
            lockF.deleteOnExit() ;
            deletionHookAdded = true ;
        }

        RandomAccessFile file = new RandomAccessFile(lockF,"rws") ;
        java.nio.channels.FileLock res = null ;
        try{
            res = file.getChannel().tryLock() ;
        }catch(OverlappingFileLockException oe){
            file.close() ;
            return null ;
        }catch(IOException e){
            System.err.println("Cannot create lock on " + lockF) ;
            file.close() ;
            throw e ;
        }

        if(res !=null && !deletionHookAdded){
            //if the file existed prior to our startup, we didn't
            //call deleteOnExit above. But since we successfully locked
            //the dir , we can take care of cleaning it up 
            lockF.deleteOnExit() ;
        }
        return res ;
    }

}

测试类

import java.io.File;
import java.io.IOException;


class Operation implements Runnable{
    private StorageDirectory sd ;
    public Operation(StorageDirectory sd){
        this.sd = sd ;
    }
    public void run() {
        try {
            System.out.println("文件加锁");
            sd.lock() ;
        } catch (Exception e) {
            System.out.println("文件加锁失败") ;
            return ;
        }
        try {
            Thread.currentThread().sleep(1000) ;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally{
            try {
                System.out.println("释放文件锁");
                sd.unlock() ;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

}

public class Main { 
   

    /** * @param args */
    public static void main(String[] args) throws Exception{
        File dir = new File("G:\\eclipse-SDK-4.2.2-win32-x86_64\\workspace\\FileLock") ;
        StorageDirectory sd1 = new StorageDirectory(dir) ;
        new Thread(new Operation(sd1)).start() ;
    // Thread.sleep(2000) ;//注释掉文件加锁失败,解开注释文件加锁成功
        StorageDirectory sd2 = new StorageDirectory(dir) ;
        new Thread(new Operation(sd2)).start() ;
    }

}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/153487.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • Mac下 Vim删除多行快捷键

    Mac下 Vim删除多行快捷键Mac下,Vi和Vim是神一样的编辑器,如何删除多行。以下以编辑host文件为例首先在Terminal中,输入vim/etc/hosts,按return。进入vim的默认模式。Vim有三种模式命令模式,编辑模式,和默认模式按esc进入命令模式,可以使用退出,存盘退出,不存盘退出等命令。命令模式稍后整理按a进入编辑模式的ins

  • linux shell 脚本 入门到实战详解[⭐建议收藏!!⭐]

    linux shell 脚本 入门到实战详解[⭐建议收藏!!⭐]文章目录shell入门到实战详解[⭐建议收藏!!⭐]关于作者**作者介绍**一、shell入门简介1.1什么是shell1.2shell编程注意事项1.3第一个shell脚本helloworld二、shell环境变量讲解2.1shell变量详解2.2shell系统变量介绍2.3shell环境变量介绍2.3.1常见的系统环境变量2.4shell用户环境变量介绍2.4.1自定义shell环境变量2.4.2echo打印菜单栏2.4.3shell中彩色输出h

  • Linux中查看进程状态信息

    Linux中查看进程状态信息Linux中查看进程状态信息一、常用命令总结ps-l列出与本次登录有关的进程信息;ps-aux查询内存中进程信息;ps-aux|grep***查询***进程的详细信息;top查看内存…

  • python fileinputstream_fileinputstream读取网络文件

    python fileinputstream_fileinputstream读取网络文件JavaIO:网络原文链接作者:JakobJenkov译者:李璟(jlee381344197@gmail.com)校对:方腾飞Java中网络的内容或多或少的超出了JavaIO的范畴。关于Java网络更多的是在我的Java网络教程中探讨。但是既然网络是一个常见的数据来源以及数据流目的地,并且因为你使用…文章ali清英2016-04-061054浏览量JavaIO:网络Jav…

  • Sexy Beach PR 汉化补丁+入门教程

    Sexy Beach PR 汉化补丁+入门教程【遊戲名稱/Name】:SexyBeachPR【遊戲廠商/Company】:Illusion【發售日期/Saledate】:2015-9-11〓补丁说明:〓※本补丁为Illusion出

  • pytest重试_pytest失败重跑

    pytest重试_pytest失败重跑安装:pip3installpytest-rerunfailures重新运行所有失败用例要重新运行所有测试失败的用例,请使用–reruns命令行选项,并指定要运行测试的最大次数:$py

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号