设计模式以在同一对象运行回调时重新创建对象



这是我试图做的一个愚蠢的玩具示例。

我有一个 WebSocket 类,它实现了方法onClose()。当套接字关闭时,它会触发事件处理程序(lambda 函数(。

public class WebSocket {
ICallback cb;
public WebSocket(ICallback cb) {
this.cb = cb;
this.onClose(); // Simulating socket closing
}
public void onClose() {
this.cb.handle();
}
@FunctionalInterface
public static interface ICallback {
public abstract void handle();
}
}

在父类中,我创建了此类的新实例。当套接字关闭时,我必须重新创建此类的新实例。 (旧的无法使用(

这是我的实现

class Parent {
static WebSocket socket;
public static void main(String[] args) {
Parent.createSocket();
}
public static void createSocket() {
Parent.socket = new WebSocket(() -> { Parent.createSocket(); });
}
}

此代码有效

但是,每当触发onClose()时,都会向堆栈添加一个新帧。如果让其运行足够长的时间并假设许多错误导致套接字关闭,则最终会导致StackOverflowError

运行示例

在不增加堆栈大小的情况下重新创建WebSocket对象的最佳模式是什么?

运行持续检查套接字状态的线程是否是一种可行的方法? 即:

while(socket.isOpen()) {
Thread.sleep(1000);
}
createSocket();

堆栈溢出的原因是您的回调永远不会完成 - 您只需创建一个新套接字并运行它,但旧套接字保持活动状态。下一个也一样,依此类推。

因此,处理此问题的一种方法是同时创建套接字,以便为onClose()方法提供实际终止的方法。

你可以通过将实际的创建提交到一个ExecutorService来做到这一点;单线程的很好,因为毕竟,你只希望在给定的时间运行一个套接字。

class Parent {
static WebSocket socket;
// this is where the socket runs
private static final ExecutorService EXECUTOR = Executors.newSingleThreadExecutor();
public static void main(String[] args) {
createSocket();
}
private static void createSocket() {
Parent.socket = new WebSocket(() -> {
EXECUTOR.submit(Parent::createSocket);
});
}
}

这样,当回调被onClose()调用时,它会立即返回,并提交创建新的 Web 套接字。该创建尚未发生,因为执行器是单线程的,并且以前的套接字仍在该线程中运行。但是一旦完成,就会执行下一个提交 - 即刚刚提交的创建。

作为旁注,同时运行网络连接几乎总是一个好主意,因此主线程仍可用于其他任务。

最新更新