3

我想创建一个可以检测自身其他实例并阻止它们运行的​​应用程序。为了实现这一点,我正在考虑在某个特定于应用程序的端口上打开一个新ServerSocket端口,然后依靠如果我尝试多次绑定到同一个端口来“检测”并杀死重复的应用程序时应该抛出的异常实例。我知道我可以做一些事情,比如将一个文件写入当前工作目录并“检测”它以完成同样的行为,但我真的不想这样做(如果应用程序死了会发生什么) t 删除文件?),这就是我选择这ServerSocket条路线的原因。

假设我有以下代码:

public class MyClass{
    public static void main(String[] args) throws IOException{
        new ServerSocket(1234);

        new Thread(){
            //This is a non-daemon thread. Assume its run() method never returns.
        }.start();
    }
}

问题

如果没有创建ServerSocket,我的应用程序永远不需要再次使用它,因为它的存在使我能够检测到我的应用程序的另一个实例何时尝试启动。因此,保存对 said 的引用ServerSocket将导致编译警告(未使用的引用)。我是一个整洁的怪胎,所以如果可以避免的话,我宁愿不保存参考。我的问题是,这个ServerSocket实例是否会在所有非守护线程退出之前被垃圾收集(假设应用程序没有失败或以其他方式退出),如果是这样,它的关联端口是否会因此变得未绑定?

4

2 回答 2

4

我很困惑:你是一个“整洁的怪胎”,但宁愿让套接字关闭垃圾收集器的心血来潮,也不愿在正常退出的情况下在应用程序的控制下关闭程序?(我认为是这种情况,因为要建立这样的机制,您需要持有参考,从而消除您认为的问题。)

对于它的价值,如果您不坚持参考,我认为实际上不会有问题:

  • 在内部,可能会在绑定套接字时保留引用
  • ServerSocket 的 close() 方法很可能会在垃圾收集时被调用。它在 AbstractPlainSocketImpl 的 finalize() 方法中调用,因此原则上会被调用,但不能保证任何 finalize 方法都会被实际调用。
  • 如果应用程序异常终止,则无法保证套接字会立即解除绑定尽管在最近的 O/S 上可能会(最好对此进行测试)。

但是,我真的建议为您的应用程序完全关闭的情况编写一个“干净的”关闭机制,为此您需要保留对套接字的引用。因此,我认为您确实在为自己发明一个问题,如果您只是使用明智的编程实践,那么这个问题就不需要存在。

于 2012-05-22T00:19:15.910 回答
1

好吧,让我试着从我之前的错误理解中解脱出来。您提到的文件锁定和套接字技术被广泛使用,但还有另一种 - 有一个观察者将保留您的程序的当前实例(通过方法注册和注销)。

如果一个新实例尝试注册,而另一个实例正在运行,则注册过程将失败,您的应用程序可以正常关闭。

然后,您的应用程序可以实现一个 Observable 接口,该接口将包含一个方法 beObserved 以便您的观察者知道您的应用程序仍然存在。因此,如果您的应用程序崩溃,定期检查将失败,它会自动注销崩溃的应用程序。

于 2012-05-22T12:05:12.143 回答