简体   繁体   中英

How to avoid Stack Overflow errors in infinitely recursive method?

I know there are tons of posts about stack overflow errors and i understand why my specific one is happening, my question is basically how to move away from recursion in this specific case. I have a class which establishes and maintains a client connection (for HL7 messaging specifically but it's essentially a glorified client connection) to another system which hosts corresponding server connections. This class' constructor starts a new thread and runs the following method :

@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)
        {}
    }
}

Upon successfully connecting with the server, the monitor method simply checks, in yet another thread, if the connection is still up at a given interval. If it goes down, the monitoring thread is interrupted and the connect() method is called again.

I did not anticipate this at first but you can quickly see why the connect() method is causing stack overflow errors after several days running. I'm struggling to think of a way to get the same functionality to work without the connect method calling itself again every time the connection fails.

Any suggestions would be appreciated.

Thanks!

Typically you'd use a Stack object to emulate recursion when required.

However, in your case, why are you using recursion at all? A while loop fits the purpose.

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

I'm not sure of the purpose of your application, but there are may be better methods than sleeping. You could use a ScheduledExecutorService , but if it's a single threaded program with one purpose it's probably unnecessary.

I changed my code to an iterative approach as suggested, works beautifully!

@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();
}

When I had to deal with this issue in c# I used a Stack, and added new classes to it, instead of using recursion. Then a second loop would check to see if there were any objects in the stack that needed dealing with. That avoided stack overflow when I would have had huge amounts of recursion otherwise. Is there a similar Stack collection in Java?

Why are you calling the monitor() method in the first place? You mention that it is launched in a separate thread, then can't you just launch it in a new thread when the application comes up? Then there won't be a recursive call.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM