如何避免无限递归方法中的堆栈溢出错误?
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();
}
我知道有很多关于堆栈溢出错误的帖子,我明白为什么我的特定错误会发生,我的问题基本上是如何在这种特定情况下摆脱递归。我有一个 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();
}