这是我正在尝试做的事情的一个简单的玩具示例。
我有一个 WebSocket 类,它实现了方法 onClose()
。当 Socket 关闭时,它会触发一个事件处理程序(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。
<强> Running Example
在不增加堆栈大小的情况下重新创建 WebSocket
对象的最佳模式是什么?
运行一个连续检查套接字状态的线程是一种可行的方法吗? 即:
while(socket.isOpen()) {
Thread.sleep(1000);
}
createSocket();
最佳答案
堆栈溢出的原因是您的回调永远不会完成 - 您只需创建一个新套接字并运行它,但旧套接字保持 Activity 状态。下一张也一样,依此类推。
因此,处理此问题的一种方法是同时创建套接字,为 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 套接字的创建。该创建尚未发生,因为执行器是单线程的,并且先前的套接字仍在该线程中运行。但一旦完成,就会执行下一次提交 - 即刚刚提交的创建。
顺便说一句,同时运行网络连接几乎总是一个好主意,因此主线程仍然可用于其他任务。
关于java - 当同一对象运行回调时重新创建对象的设计模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57518650/