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() ;
    }

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

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

赞 (0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 面试题vue双向绑定原理_vue路由面试题

    面试题vue双向绑定原理_vue路由面试题引言:vue的双向绑定原理简单来说就是:vue内部使用object.defineProperty方法给所有数据加上getter和setter方法,在数据发生改变时发布消息给订阅者Watcher,触发响应的监听回调。object.defineProperty是JS里一个重要的方法,vue的双向绑定ES6里一些方法都是靠它实现的。如图所示zuoerobject.defineProperty…

    2022年10月17日
  • SLAM机器人开发(二)SLAM技术现状

    SLAM机器人开发(二)SLAM技术现状SLAM机器人开发(二)SLAM技术现状激光SLAM2D激光SLAM3D激光SLAM视觉SLAM常见的视觉SLAM视觉SLAM对比视觉SLAM中使用的相机种类视觉SLAM效果图视觉激光融合SLAM激光SLAM2D激光SLAM激光SLAM在SLAM技术中是较为传统且成熟的。2D激光SLAM技术需要输入IMU数据、里程计数据和2D激光雷达数据,经过计算后输出覆盖栅格地图和机器人轨迹。从20世纪90年代EKF-SLAM的提出开始,陆续出现了UKF-SLAM、PF-S

    2022年10月1日
  • C语言-判断回文字符串(二)

    C语言-判断回文字符串(二)7-2 判断回文字符串 (15分)输入一个字符串,判断该字符串是否为回文。回文就是字符串中心对称,从左向右读和从右向左读的内容是一样的。输入格式:输入在一行中给出一个不超过80个字符长度的、以回车结束的非空字符串。输出格式:输出在第1行中输出字符串。如果它是回文字符串,在第2行中输出Yes,否则输出No。输入样例1:level输出样例1:levelYe…

    2022年5月30日
  • android之interpolator的用法详解

    android:interpolator    Interpolator 被用来修饰动画效果,定义动画的变化率,可以使存在的动画效果accelerated(加速),decelerated(减速),repeated(重复),bounced(弹跳)等。  android中的文档内容如下:   AccelerateDecelerateInterpolator 在动画开始与介绍的地

    2022年3月10日
  • python遍历本地文件系统 按文件大小排序

    python遍历本地文件系统 按文件大小排序

    2021年11月21日
  • windows环境下tomcat部署war包[通俗易懂]

    windows环境下tomcat部署war包[通俗易懂]1.从Eclipse中将项目打包成war包,Runas&gt;&gt;MavenInstall,然后将war包放在tomcat\webapps下,如图所示2.然后运行tomcat\bin目录下的startup.bat(运行后悔在webapps下生成相应名称的目录)3.运行成功,使用Postman测试成功…

    2022年6月2日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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