【问题标题】:How to acquire FileLock without resource warning?如何在没有资源警告的情况下获取 FileLock?
【发布时间】:2018-06-19 20:25:35
【问题描述】:

我有以下代码:

try {
    final Path lock = Files.write(PATH_TO_FILE_IN_A_CONSTANT, "Executing Job", StandardOpenOption.CREATE, StandardOpenOption.WRITE);

    final RandomAccessFile raf = new RandomAccessFile(lock.toFile(), "r");
    FileLock fl = new FileInputStream(raf.getFD()).getChannel().lock(0, Long.MAX_VALUE, true);
} catch (final IOException e) {
    LOGGER.error("Error while trying to write file. ERROR: " + e.getMessage(), e);

    Runtime.getRuntime().exit(-1);
}

问题是,由于我没有关闭RandomAccessFileInputStreamCloseable's 对象我收到警告说我没有关闭对象,这可能会导致资源泄漏。如果我关闭此对象,文件将失去授予的锁定。我需要在作业执行时锁定文件,然后删除它。

我可以使用SuppressWarnings"resource"annotation,但我没有这样做,而是尝试研究解决方案,但不幸的是我没有得到任何成功。

有没有办法获取锁而没有收到这个警告?

【问题讨论】:

  • 所以你在这里锁定文件?然后 ?您在哪里使用该文件以及何时释放锁定?编译器警告是出于某种原因构建的,拇指规则,打开资源,锁定它,使用/读取它,并在完成后关闭它。这些是您使用任何分配的资源作为单个工作单元执行的任务序列。如果编译器看到循环没有完成,它就在抱怨资源泄漏。
  • @AmithKumar,正如我所说,我需要在批处理执行的整个过程中锁定文件,一旦工作完成,我在 shutdownHook 中添加了锁定释放。
  • 你为什么要绕道开FileChannel?即使你不使用FileChannel.open直接打开通道,RandomAccessFile有一个getChannel()方法,另一方面,你可以打开一个FileInputStream而不用先打开一个RandomAccessFile。所以从来没有理由打开三个资源来获得锁。而如果你使用FileChannel.open,你只需要保留和关闭频道。
  • 而且你必须保留 FileChannel 并在适当的时候关闭它,因为当你不这样做时,垃圾收集器可能会完全这样做不可预知的时间点。
  • @AmithKumar,实际上使用FileChannel.open 并没有给我锁,但是使用RandomAccessFile 它是成功的。我不知道RandomAccessFile 中的'getChannel 方法。谢谢!关于为什么 FileChannel.open 不起作用的任何线索?

标签: file java-8 path file-locking


【解决方案1】:

没有IO操作是无法实现文件锁的,IO操作需要一定的闭包,否则编译器会报错。您将不得不调整您的方法以实现解决方案:

public class FileLockMaster {
    //easy way to use ThreadLocal, if the batch threads are child to this thread, set release in batch shutdownHook
    InheritableThreadLocal<Lock> lock = new InheritableThreadLocal<>(); 
    //or you can create a instance or static variable here to be set in child batch threads in shutdownHook,
    //depending on batch threads will have access to instance or not respectively


    public void acquireFileLock(){
        Path PATH_TO_FILE_IN_A_CONSTANT = null;
        byte[] Executing_Job = null;
        RandomAccessFile raf = null;
        FileLock fl = null;
        FileInputStream fStream = null;
        //or you can use try with resources with while() loop inside try block
        try {
            final Path lock = Files.write(PATH_TO_FILE_IN_A_CONSTANT, Executing_Job, StandardOpenOption.CREATE, StandardOpenOption.WRITE);
            raf = new RandomAccessFile(lock.toFile(), "r");
            fStream = new FileInputStream(raf.getFD()); 
            fl = fStream.getChannel().lock(0, Long.MAX_VALUE, true);

            /**
             * create batch threads here or outside to complete the job
             */

        } catch (final IOException e) {
            LOGGER.error("Error while trying to write file. ERROR: " + e.getMessage(), e);
            Runtime.getRuntime().exit(-1);
        } finally{
            try {
                while (true) {
                    if (this.lock.get().release) {
                        raf.close();
                        fStream.close();
                        fl.close();
                        break;
                    }
                }
            } catch (Exception e){
                //ignore
            }
    }
}

class Lock{
    boolean release;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-10-29
    • 2015-02-25
    • 2021-11-22
    • 2019-05-14
    • 2011-05-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多