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

如何让Windows下的Java JFrame应用仅运行单个实例?

强制Windows系统中Java JFrame应用仅运行单个实例的实现方法

要让Windows下的Java JFrame应用只能运行一个实例,常用两种可靠方案,结合你的代码示例具体实现如下:

方案一:跨平台文件锁机制(Windows兼容)

通过尝试锁定一个专属文件来判断是否已有实例在运行,成功获取锁则继续启动,失败则直接退出。这种方法无需依赖平台特定API,跨平台通用。

修改你的Home类,在main方法中加入单实例检查逻辑:

import java.io.File;
import java.io.RandomAccessFile;
import java.nio.channels.FileLock;
import javax.swing.JOptionPane;
import java.awt.EventQueue;

public class Home {
    private static FileLock lock;
    private JFrame frame;
    private JTextField txtUsername;

    public Home() {
        initialize();   
    }       

    public static void main(String[] args) {
        // 检查是否已有实例运行
        if (!checkSingleInstance()) {
            JOptionPane.showMessageDialog(null, "应用已在运行中!");
            System.exit(0);
        }

        EventQueue.invokeLater(() -> {
            try {
                Home window = new Home();
                window.frame.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    private static boolean checkSingleInstance() {
        try {
            // 选择用户目录下的隐藏锁文件,避免误删
            File lockFile = new File(System.getProperty("user.home"), ".myapp_single_instance.lock");
            RandomAccessFile raf = new RandomAccessFile(lockFile, "rw");
            lock = raf.getChannel().tryLock();
            
            if (lock == null) {
                // 无法获取锁,说明已有实例存在
                raf.close();
                return false;
            }

            // 程序退出时自动释放锁并删除文件
            Runtime.getRuntime().addShutdownHook(new Thread(() -> {
                try {
                    lock.release();
                    raf.close();
                    lockFile.delete();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }));
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    private void initialize() {
        frame = new JFrame();
        frame.getContentPane().addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                // 自定义点击事件逻辑
            }
        });
        frame.getContentPane().setBackground(Color.DARK_GRAY);
        frame.getContentPane().setLayout(null);
        
        txtUsername = new JTextField();
        txtUsername.setBorder(null);
        txtUsername.setBackground(Color.DARK_GRAY);
        txtUsername.setForeground(Color.WHITE);
        txtUsername.addFocusListener(new FocusAdapter() {
            // 自定义焦点事件逻辑
        });
        // 其他初始化代码...
    }

    // 其他自定义方法...
}

注意事项:锁文件路径要选不易被用户误操作删除的位置,比如用户主目录下的隐藏文件,确保锁的有效性。

方案二:Windows专属系统互斥体

利用Windows系统级互斥体机制,通过JNA调用Windows API创建唯一互斥体,新实例检测到互斥体已存在时直接退出。这种方式是Windows平台专属,可靠性更强,不会因锁文件被删除而失效。

第一步:引入JNA依赖

如果使用Maven,在pom.xml中添加:

<dependency>
    <groupId>net.java.dev.jna</groupId>
    <artifactId>jna</artifactId>
    <version>5.13.0</version>
</dependency>
<dependency>
    <groupId>net.java.dev.jna</groupId>
    <artifactId>jna-platform</artifactId>
    <version>5.13.0</version>
</dependency>

第二步:修改代码实现单实例控制

import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.WinBase;
import com.sun.jna.platform.win32.WinNT;
import javax.swing.JOptionPane;
import java.awt.EventQueue;

public class Home {
    private static WinNT.HANDLE mutexHandle;
    private JFrame frame;
    private JTextField txtUsername;

    public Home() {
        initialize();   
    }       

    public static void main(String[] args) {
        // 定义全局唯一的互斥体名称,避免与其他应用冲突
        String mutexName = "Global\\MyApp_Unique_Mutex";
        mutexHandle = Kernel32.INSTANCE.CreateMutexW(null, true, mutexName);
        
        // 检查互斥体是否已存在
        if (Kernel32.INSTANCE.GetLastError() == WinBase.ERROR_ALREADY_EXISTS) {
            JOptionPane.showMessageDialog(null, "应用已在运行中!");
            Kernel32.INSTANCE.CloseHandle(mutexHandle);
            System.exit(0);
        }

        // 程序退出时关闭互斥体
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            if (mutexHandle != null) {
                Kernel32.INSTANCE.CloseHandle(mutexHandle);
            }
        }));

        EventQueue.invokeLater(() -> {
            try {
                Home window = new Home();
                window.frame.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    private void initialize() {
        // 你的初始化代码...
        frame = new JFrame();
        frame.getContentPane().addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                // 自定义点击事件逻辑
            }
        });
        frame.getContentPane().setBackground(Color.DARK_GRAY);
        frame.getContentPane().setLayout(null);
        
        txtUsername = new JTextField();
        txtUsername.setBorder(null);
        txtUsername.setBackground(Color.DARK_GRAY);
        txtUsername.setForeground(Color.WHITE);
        txtUsername.addFocusListener(new FocusAdapter() {
            // 自定义焦点事件逻辑
        });
        // 其他初始化代码...
    }

    // 其他自定义方法...
}

注意事项:互斥体名称要保证全局唯一,建议使用公司标识+应用名称的组合,加上Global\\前缀可以在多用户登录环境下限制整个系统只能运行一个实例。

内容的提问来源于stack exchange,提问作者Ramil H. Bercasio

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 20:25:12