Java 线程在没有 Exception/Throwable 的情况下停止
Java Thread stops without Exception/Throwable
我有一个非常恼人的问题,我无法自己解决。
我有一个简单的 JavaFX 场景,只有 2 个按钮用于启动和终止线程。在这种情况下,停止操作不相关,因为我无法使线程正常工作。 actionListener 看起来像:
EDIT1: 弄清楚了问题,它 不是 线程特定的,它是针对 TimeServer 的请求,请看这里:
感谢所有回答此问题或阅读问题的人! :)
private FarmAction action = null;
@FXML
void btnStartListener(ActionEvent event) {
Firefox ff = new Firefox();
ff.startBrowser();
BrowserAction browserAction = new BrowserAction(ff.getDriver(), ff.getJse());
browserAction.loginToGame(user, pass);
ObservableList<AttackCommand> list = (ObservableList<AttackCommand>) Serializer.deserialize(Constants.FILE_NAME_TESTPURPOSE);
if(action == null)
action = new FarmAction(ff.getDriver(), ff.getJse(), list);
Thread run = new Thread(action);
try {
run.start();
} catch (Exception e) {
e.printStackTrace();
} catch (Throwable t) {
t.printStackTrace();
}
}
注意:我正在使用 Selenium Framework 来自动执行一些点击
网站。
我的 FarmAction class 看起来像这样:
public class FarmAction implements Runnable{
private WebDriver driver;
private JavascriptExecutor jse;
private ObservableList<AttackCommand> attackList;
private boolean stop = false;
public FarmAction(WebDriver driver, JavascriptExecutor jse, ObservableList<AttackCommand> attackList) {
this.driver = driver;
this.jse = jse;
for(AttackCommand ac : attackList)
{
ac.transferFromPropToAttributes();
}
this.attackList = attackList;
}
@Override
public void run() {
ArrayList<Integer> unitIds = Constants.UNIT_ID_LIST_ALL;
if(!driver.getCurrentUrl().equals(Constants.URL_TESTPURPOSE))
driver.navigate().to(Constants.URL_TESTPURPOSE);
int count = 0;
while(true) { // Just let the Thread run for duration = lifetime of application
System.out.println(count++); //count how often the thread runs into this while loop before terminating for no reason
for(AttackCommand ac : attackList) {
for(int i = 0; i < unitIds.size(); i ++) {
int unitKey = unitIds.get(i); // Momentane UnitID der Iteration
if(ac.getUnits().containsKey(unitKey) && ( ac.getTurnBackTime() == 0 ||ac.getTurnBackTime() <= DateUtil.getActualServerTime())) // getActualServerTime is request against the timeserver de.pool.ntp.org
{
String textfieldName = Constants.HASHMAP_TEXTFIELD_NAME_ALL_HTML_PLACE.get(unitKey);
WebElement textfield = driver.findElement(By.name(textfieldName));
textfield.sendKeys(String.valueOf(ac.getUnits().get(unitKey)));
WebElement textfieldCoordinates = driver.findElement(By.name(Constants.TEXTFIELD_NAME_HTML_PLACE_COODRINATESFORTARGET));
textfieldCoordinates.sendKeys(StringHelper.getPointAsString(new Point(ac.getXCoordinates(), ac.getYCoordinates())));
WebElement submitButton = driver.findElement(By.id(Constants.TA));
submitButton.click();
WebElement sndAttackSubmitButton = driver.findElement(By.name(Constants.SBM));
WebElement span = driver.findElement(By.className(Constants.CLASSNAME_TIME));
long duration = Long.parseLong(span.getAttribute(Constants.ATTRIBUTE_DURATION));
sndAttackSubmitButton.click();
ac.setStartTime(DateUtil.getActualServerTime());
ac.setDurationInSeconds(duration*1000);
ac.setTurnBackTime(ac.getStartTime()+ac.getDurationInSeconds());
}
}
}
}
}}
如您所见,我已将 Thread.start() 方法包装到 Throwables AND Exceptions 的 try-catch 中,但如果线程无故停止,我不会得到任何 Stacktrace。我预计会出现 Whosebug 错误,但我什么也没发现。
我的线程运行的循环数量非常不同。有时它会在 12 后停止,有时会在 370 或 59 后停止。所有值都是示例 - 每次都不同。
你知道我做错了什么吗?
提前致谢!
您需要检查 Thread
class 的 run()
方法中的异常。
调用start()
方法后,创建的线程有自己的栈,不同于主线程的栈,start()
方法是从这里调用的。
因此,在线程的 run()
方法中抛出的异常,对于与 start()
方法相关的 catch
语句是不可见的。
正如@Immibis 在评论中提到的那样,在 thread.start()
附近捕获异常没有任何意义,因为它会立即 return。
检查异常的一种方法是使用 UncaughtExceptionHandler
,它看起来像这样:
Thread run = new Thread(action);
run.setUncaughtExceptionHandler(
new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
e.printStackTrace();
}
}
);
run.start();
好的,我已经解决了问题。它不是特定于线程的,很抱歉,但是由于您的回答,我对线程有了更多的了解 :) 谢谢大家!
我已经将 SystemOuts 放在每个代码行后面,并在 25 次运行和冻结后发现有两个可能的代码行线程停止工作:
两条语句都使用了我的 DateUtil.getActualServerTime()
方法,如下所示:
public static long getActualServerTime() {
String TIME_SERVER = "de.pool.ntp.org";
NTPUDPClient timeClient = new NTPUDPClient();
InetAddress inetAddress;
long returnTime = 0;
try {
inetAddress = InetAddress.getByName(TIME_SERVER);
TimeInfo timeInfo = timeClient.getTime(inetAddress);
returnTime = timeInfo.getMessage().getTransmitTimeStamp().getTime();
} catch (Exception e) {
e.printStackTrace();
} catch (Throwable t) {
t.printStackTrace();
}
return returnTime;
}
我正在为此使用 apache.commons.net 库。
如果我只是 return
Date d = new Date(); return d.getTime();
在我手动停止它之前,我的线程在大约 60.000 个循环中工作正常。
我在这里也没有得到 Exception 或 Throwable。我会说在特定时间或类似时间对时间服务器的请求量最大。我现在无法在网站上找到它。
我也有同样的问题,我的线程没有任何内容就终止了exception/throwable。
我有一个接受套接字的线程(nio,但是blocking-mode)。如果套接字接收请求的速度很慢,但是当一次接收很多请求时,线程运行良好停止。
我在linux中更改了几个选项,比如mem [net.ipv4.tcp_rmem, net.core.wmem_default, net.ipv4.tcp_mem],可能是为了这个?
我有一个非常恼人的问题,我无法自己解决。
我有一个简单的 JavaFX 场景,只有 2 个按钮用于启动和终止线程。在这种情况下,停止操作不相关,因为我无法使线程正常工作。 actionListener 看起来像:
EDIT1: 弄清楚了问题,它 不是 线程特定的,它是针对 TimeServer 的请求,请看这里:
感谢所有回答此问题或阅读问题的人! :)
private FarmAction action = null;
@FXML
void btnStartListener(ActionEvent event) {
Firefox ff = new Firefox();
ff.startBrowser();
BrowserAction browserAction = new BrowserAction(ff.getDriver(), ff.getJse());
browserAction.loginToGame(user, pass);
ObservableList<AttackCommand> list = (ObservableList<AttackCommand>) Serializer.deserialize(Constants.FILE_NAME_TESTPURPOSE);
if(action == null)
action = new FarmAction(ff.getDriver(), ff.getJse(), list);
Thread run = new Thread(action);
try {
run.start();
} catch (Exception e) {
e.printStackTrace();
} catch (Throwable t) {
t.printStackTrace();
}
}
注意:我正在使用 Selenium Framework 来自动执行一些点击 网站。
我的 FarmAction class 看起来像这样:
public class FarmAction implements Runnable{
private WebDriver driver;
private JavascriptExecutor jse;
private ObservableList<AttackCommand> attackList;
private boolean stop = false;
public FarmAction(WebDriver driver, JavascriptExecutor jse, ObservableList<AttackCommand> attackList) {
this.driver = driver;
this.jse = jse;
for(AttackCommand ac : attackList)
{
ac.transferFromPropToAttributes();
}
this.attackList = attackList;
}
@Override
public void run() {
ArrayList<Integer> unitIds = Constants.UNIT_ID_LIST_ALL;
if(!driver.getCurrentUrl().equals(Constants.URL_TESTPURPOSE))
driver.navigate().to(Constants.URL_TESTPURPOSE);
int count = 0;
while(true) { // Just let the Thread run for duration = lifetime of application
System.out.println(count++); //count how often the thread runs into this while loop before terminating for no reason
for(AttackCommand ac : attackList) {
for(int i = 0; i < unitIds.size(); i ++) {
int unitKey = unitIds.get(i); // Momentane UnitID der Iteration
if(ac.getUnits().containsKey(unitKey) && ( ac.getTurnBackTime() == 0 ||ac.getTurnBackTime() <= DateUtil.getActualServerTime())) // getActualServerTime is request against the timeserver de.pool.ntp.org
{
String textfieldName = Constants.HASHMAP_TEXTFIELD_NAME_ALL_HTML_PLACE.get(unitKey);
WebElement textfield = driver.findElement(By.name(textfieldName));
textfield.sendKeys(String.valueOf(ac.getUnits().get(unitKey)));
WebElement textfieldCoordinates = driver.findElement(By.name(Constants.TEXTFIELD_NAME_HTML_PLACE_COODRINATESFORTARGET));
textfieldCoordinates.sendKeys(StringHelper.getPointAsString(new Point(ac.getXCoordinates(), ac.getYCoordinates())));
WebElement submitButton = driver.findElement(By.id(Constants.TA));
submitButton.click();
WebElement sndAttackSubmitButton = driver.findElement(By.name(Constants.SBM));
WebElement span = driver.findElement(By.className(Constants.CLASSNAME_TIME));
long duration = Long.parseLong(span.getAttribute(Constants.ATTRIBUTE_DURATION));
sndAttackSubmitButton.click();
ac.setStartTime(DateUtil.getActualServerTime());
ac.setDurationInSeconds(duration*1000);
ac.setTurnBackTime(ac.getStartTime()+ac.getDurationInSeconds());
}
}
}
}
}}
如您所见,我已将 Thread.start() 方法包装到 Throwables AND Exceptions 的 try-catch 中,但如果线程无故停止,我不会得到任何 Stacktrace。我预计会出现 Whosebug 错误,但我什么也没发现。
我的线程运行的循环数量非常不同。有时它会在 12 后停止,有时会在 370 或 59 后停止。所有值都是示例 - 每次都不同。
你知道我做错了什么吗?
提前致谢!
您需要检查 Thread
class 的 run()
方法中的异常。
调用start()
方法后,创建的线程有自己的栈,不同于主线程的栈,start()
方法是从这里调用的。
因此,在线程的 run()
方法中抛出的异常,对于与 start()
方法相关的 catch
语句是不可见的。
正如@Immibis 在评论中提到的那样,在 thread.start()
附近捕获异常没有任何意义,因为它会立即 return。
检查异常的一种方法是使用 UncaughtExceptionHandler
,它看起来像这样:
Thread run = new Thread(action);
run.setUncaughtExceptionHandler(
new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
e.printStackTrace();
}
}
);
run.start();
好的,我已经解决了问题。它不是特定于线程的,很抱歉,但是由于您的回答,我对线程有了更多的了解 :) 谢谢大家!
我已经将 SystemOuts 放在每个代码行后面,并在 25 次运行和冻结后发现有两个可能的代码行线程停止工作:
两条语句都使用了我的 DateUtil.getActualServerTime()
方法,如下所示:
public static long getActualServerTime() {
String TIME_SERVER = "de.pool.ntp.org";
NTPUDPClient timeClient = new NTPUDPClient();
InetAddress inetAddress;
long returnTime = 0;
try {
inetAddress = InetAddress.getByName(TIME_SERVER);
TimeInfo timeInfo = timeClient.getTime(inetAddress);
returnTime = timeInfo.getMessage().getTransmitTimeStamp().getTime();
} catch (Exception e) {
e.printStackTrace();
} catch (Throwable t) {
t.printStackTrace();
}
return returnTime;
}
我正在为此使用 apache.commons.net 库。
如果我只是 return
Date d = new Date(); return d.getTime();
在我手动停止它之前,我的线程在大约 60.000 个循环中工作正常。
我在这里也没有得到 Exception 或 Throwable。我会说在特定时间或类似时间对时间服务器的请求量最大。我现在无法在网站上找到它。
我也有同样的问题,我的线程没有任何内容就终止了exception/throwable。
我有一个接受套接字的线程(nio,但是blocking-mode)。如果套接字接收请求的速度很慢,但是当一次接收很多请求时,线程运行良好停止。
我在linux中更改了几个选项,比如mem [net.ipv4.tcp_rmem, net.core.wmem_default, net.ipv4.tcp_mem],可能是为了这个?