如何避免无限递归方法中的堆栈溢出错误?

How to avoid Stack Overflow errors in infinitely recursive method?

我知道有很多关于堆栈溢出错误的帖子,我明白为什么我的特定错误会发生,我的问题基本上是如何在这种特定情况下摆脱递归。我有一个 class,它建立并维护一个客户端连接(专门用于 HL7 消息传递,但它本质上是一个美化的客户端连接)到另一个托管相应服务器连接的系统。此 class' 构造函数启动一个新线程并运行以下方法:

@Override
public void connect() 
{
    try
    {
        setStatus("Connecting");

        connection = context.newClient(intfc.getIp(), port, false);
        connected = true;
        setStatus("Connected");

        logEntryService.logInfo(LogEntry.CONNECTIVITY, "Successfully connected " + connectionType + " client connection to " 
                + intfc.getName() + "(" + intfc.getIp() + ") on port " + port);

        monitor();
    }
    catch (HL7Exception ex)
    {
        connected = false;
        setStatus("Disconnected");

        try
        {
            TimeUnit.SECONDS.sleep(connectionRetryIntervalInSeconds);
            connect();
        }
        catch (InterruptedException ex2)
        {}
    }
}

与服务器成功连接后,monitor 方法会在另一个线程中简单地检查连接是否仍处于给定时间间隔。如果宕机,则监听线程中断,再次调用connect()方法。

起初我没有预料到这一点,但您很快就会明白为什么 connect() 方法在几天后导致堆栈溢出错误 运行。我正在努力想出一种方法来获得相同的功能,而无需每次连接失败时 connect 方法再次调用自身。

如有任何建议,我们将不胜感激。

谢谢!

当我不得不在 c# 中处理这个问题时,我使用了一个堆栈,并向其中添加了新的 类,而不是使用递归。然后第二个循环将检查堆栈中是否有任何需要处理的对象。这避免了堆栈溢出,否则我会进行大量递归。 Java中是否有类似的Stack集合?

通常您会在需要时使用 Stack 对象来模拟递归。

但是,在您的情况下,您为什么要使用递归? while 循环符合目的。

while(true /**or some relevant condition**/){
   try{ //try to connect
      ....
   catch(HL7Exception ex){
      //sleep
   }
 }

我不确定你申请的目的,但可能有比睡觉更好的方法。您可以使用 ScheduledExecutorService,但如果它是一个只有一个目的的单线程程序,则可能没有必要。

为什么首先要调用 monitor() 方法?你说它是在一个单独的线程中启动的,那么你不能在应用程序上来时在一个新的线程中启动它吗?那么就不会有递归调用了。

我按照建议将代码更改为迭代方法,效果很好!

@Override
public void initThread() 
{
    initConnectionEntity();
    mainThread = new Thread()
    {
        @Override
        public void run() 
        {
            while (running)
            {
                if (!connected)
                {
                    try
                    {
                        connect();
                    }
                    catch (HL7Exception ex)
                    {
                        connected = false;
                        setStatus("Disconnected");

                        try
                        {
                            TimeUnit.SECONDS.sleep(connectionRetryIntervalInSeconds);
                        }
                        catch (InterruptedException ex2)
                        {}
                    }
                }
                try
                {
                    TimeUnit.MILLISECONDS.sleep(500);
                }
                catch (InterruptedException ex2)
                {}
            }
        }
    };
    mainThread.setName(intfc.getName() + " " + connectionType + " Main Thread");
    mainThread.start();
}

@Override
public void connect() throws HL7Exception
{
    setStatus("Connecting");

    connection = context.newClient(intfc.getIp(), port, false);
    connected = true;
    setStatus("Connected");

    logEntryService.logInfo(LogEntry.CONNECTIVITY, "Successfully connected " + connectionType + " client connection to " 
            + intfc.getName() + "(" + intfc.getIp() + ") on port " + port);

    monitor();
}

private void monitor()
{
    monitoringThread = new Thread()
    {
        @Override
        public void run() 
        {
            try
            {
                while (running)
                {
                    if (!connection.isOpen())
                    {
                        if (connected == true)
                        {
                            logEntryService.logWarning(LogEntry.CONNECTIVITY, "Lost " + connectionType + " connection to " 
                                    + intfc.getName() + "(" + intfc.getIp() + ") on port " + port);
                        }

                        connected = false;
                        setStatus("Disconnected");

                        monitoringThread.interrupt();
                    }
                    else
                    {
                        connected = true;
                    }
                    TimeUnit.SECONDS.sleep(connectionMonitorIntervalInSeconds);
                }
            }
            catch (InterruptedException ex)
            {
                logEntryService.logDebug(LogEntry.CONNECTIVITY, "Monitoring thread for " + connectionType 
                        + " connection to " + intfc.getName() + " interrupted");                         
            }
        }
    };
    monitoringThread.setName(intfc.getName() + " " + connectionType + " Monitoring Thread");
    monitoringThread.start();
}