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

}
    原文作者:java锁
    原文地址: https://blog.csdn.net/lfdanding/article/details/51698348
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞