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],可能是为了这个?