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
相关产品推荐
相关产品推荐

