You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java应用通过文件锁阻止多实例运行失效问题排查

问题根源

你代码里的FileChannel是在try-with-resources块中创建的,这个块执行完毕后通道会自动关闭,而文件锁和通道是绑定的——通道一关闭,锁就直接释放了。所以第一个实例启动后,runCheck方法执行完锁就失效了,第二个实例自然能正常获取锁运行。

从你打印的lock日志也能佐证这一点:sun.nio.ch.FileLockImpl[0:9223372036854775807 exclusive invalid],这里的invalid明确说明锁已经失效,原因就是承载它的通道被关闭了。

修复方案

要让文件锁在整个程序运行期间保持生效,必须让FileChannel一直处于打开状态,不能在runCheck方法里就关闭。把FileChannel声明为类的静态成员变量,让它的生命周期和程序一致即可。

修改后的代码如下:

import java.io.File;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.file.StandardOpenOption;

public class JustOneTest {
    // 把FileChannel声明为静态成员,保持打开状态
    private static FileChannel lockChannel;

    public static void main(String[] args) {
        runCheck();
        while (true) {
            try {
                System.out.print(".");
                Thread.sleep(5 * 60 * 1000); // 原代码sleep参数是5*60(仅300毫秒),修正为5分钟的毫秒数
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    private static void runCheck() {
        System.out.println("start check: is app running");
        final File file = new File(System.getProperty("user.home"), "khf.lock");

        try {
            // 打开通道,不放在try-with-resources里,避免自动关闭
            lockChannel = FileChannel.open(file.toPath(), 
                    StandardOpenOption.CREATE,
                    StandardOpenOption.WRITE);
            FileLock lock = lockChannel.tryLock();

            if (lock == null) {
                System.out.println("another instance is running");
                // 退出前记得关闭通道
                lockChannel.close();
                throw new Error("another instance is running");
            }

            System.out.println(lock);
            // 此时打印的lock会显示为valid状态
            
        } catch (IOException e) {
            // 异常场景下也要确保通道关闭
            if (lockChannel != null) {
                try {
                    lockChannel.close();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
            throw new Error(e);
        }
        
        System.out.println("start check completed");
    }
}
额外说明
  • 程序正常退出时,JVM会自动关闭所有未手动关闭的通道,锁也会随之释放,不用担心资源泄漏问题。
  • 原代码中Thread.sleep(5 * 60)的参数逻辑有误,我已经修正为5 * 60 * 1000,对应5分钟的休眠时长。

内容的提问来源于stack exchange,提问作者rozerro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 21:34:59