【发布时间】:2023-04-01 06:49:01
【问题描述】:
我惊讶地发现 Java 并发超时并没有停止线程中阻塞的套接字读取操作。
我使用 Selenium RemoteWebDriver 来模拟负载测试场景。我已将 Selenium 命令的执行包装在 Callable 中,并将 get() 方法与 timeout 参数一起使用。当执行的并发线程少于 3 个时,它可以完美运行,但当有 4 个或更多并发线程时,情况会恶化。一些线程在套接字读取时卡住,并且卡住的时间超过了Callable 上的超时设置。
我在网上做了一些研究,根本原因是 Selenium 代码中硬编码的 3 小时套接字超时。曾经有一个黑客可以使用反射覆盖设置,但是对于最新版本,我认为它不再是可破解的了。
我想知道是否有办法停止被外部 IO 阻塞的线程,因为我不想更改 Selenium 代码并最终不得不维护我自己的 Selenium 版本。
这是我在代码中处理线程超时的方式:
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<Long> future = null;
try {
future = executorService.submit(new Callable<Long>() {
@Override
public Long call() throws Exception {
return commandProcessor.process(row);
}
});
timeTaken = future.get(currentTimeout, TimeUnit.MILLISECONDS);
executorService.shutdown();
} catch (Exception e) {
log.error(e.getMessage(), e);
// cancel the task
if (future != null && !future.isDone()) {
future.cancel(true);
}
executorService.shutdownNow();
}
并且由于它随机超时失败,我什至创建了另一个守护线程来监视该线程并从外部将其关闭,但是当套接字读取阻塞时它仍然无法终止线程。
在try块中:
TimeoutDaemon timeoutDaemon = new TimeoutDaemon(future, executorService, timeStarted);
// put a daemon on the main execution thread so it behaves
ExecutorService daemonExecutorService = Executors.newSingleThreadExecutor();
daemonExecutorService.submit(timeoutDaemon);
TimeoutDaemon 类:
private class TimeoutDaemon implements Runnable {
private Future<?> future;
private long timeStarted;
private ExecutorService taskExecutorService;
private TimeoutDaemon(Future<?> future, ExecutorService taskExecutorService, long timeStarted) {
this.future = future;
this.timeStarted = timeStarted;
this.taskExecutorService = taskExecutorService;
}
@Override
public void run() {
boolean running = true;
while (running) {
long currentTime = System.currentTimeMillis();
if (currentTime - timeStarted > currentTimeout + 1000) {
running = false;
if (!future.isDone()) {
String message = "Command execution is taking longer (%d ms) than the current timeout setting %d. Canceling the execution.";
message = String.format(message, currentTime - timeStarted, currentTimeout);
taskExecutorService.shutdownNow();
}
} else {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
log.error("Timeout Daemon interrupted. Test may be stuck. Close stuck browser windows if any.", e);
}
}
}
}
}
【问题讨论】:
标签: java multithreading sockets selenium concurrency