无法停止使用 ExecutorService 启动的任务
抱歉,我必须打开一个新线程来描述这个问题。
今天早上我问了这个问题,已经有一些回复了,但是我的问题还是没有解决。
这次我将附上一些可运行的代码(经过简化但具有相同的问题)供您重现问题:
public class ThreadPoolTest {
public static void main(String[] args) throws Exception {
final ExecutorService taskExecutor = Executors.newFixedThreadPool(5);
Future<Void> futures[] = new Future[5];
for (int i = 0; i < futures.length; ++i)
futures[i] = startTask(taskExecutor);
for (int i = 0; i < futures.length; ++i)
System.out.println("futures[i].cancel(true): " + futures[i].cancel(true));
System.out.println("Cancel DONE.");
taskExecutor.shutdown();
}
private static Future<Void> startTask(final ExecutorService taskExecutor) {
Future<Void> f = taskExecutor.submit(new Callable<Void>() {
public Void call() throws Exception {
try {
downloadFile(new URI("http://stackoverflow.com"));
while(true) {
System.out.println(Thread.currentThread().getName() + ": " + Thread.currentThread().isInterrupted());
if(Thread.currentThread().isInterrupted())
break;
}
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
});
return f;
}
private static void downloadFile (final URI uri) throws Exception {
// if(true) return;
Socket socket = new Socket (uri.getHost(), uri.getPort() == -1 ? 80 : uri.getPort());
return;
}
}
上面的代码很可能会陷入无限循环(您可能需要多次运行代码来见证我所看到的情况) ),正如你在主方法中看到的,我为所有任务调用了 futures[i].cancel(true) ,我不知道为什么会发生这种情况,这一直在折磨我更多比一天。
我们将非常感谢您的帮助。
Sorry I have to open a new thread to describe this problem.
This morning I asked this question, there're some replies but my problem is still not solved.
This time I will attach some runnable code(simplified but with the same problem) for you to reproduce the problem:
public class ThreadPoolTest {
public static void main(String[] args) throws Exception {
final ExecutorService taskExecutor = Executors.newFixedThreadPool(5);
Future<Void> futures[] = new Future[5];
for (int i = 0; i < futures.length; ++i)
futures[i] = startTask(taskExecutor);
for (int i = 0; i < futures.length; ++i)
System.out.println("futures[i].cancel(true): " + futures[i].cancel(true));
System.out.println("Cancel DONE.");
taskExecutor.shutdown();
}
private static Future<Void> startTask(final ExecutorService taskExecutor) {
Future<Void> f = taskExecutor.submit(new Callable<Void>() {
public Void call() throws Exception {
try {
downloadFile(new URI("http://stackoverflow.com"));
while(true) {
System.out.println(Thread.currentThread().getName() + ": " + Thread.currentThread().isInterrupted());
if(Thread.currentThread().isInterrupted())
break;
}
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
});
return f;
}
private static void downloadFile (final URI uri) throws Exception {
// if(true) return;
Socket socket = new Socket (uri.getHost(), uri.getPort() == -1 ? 80 : uri.getPort());
return;
}
}
The code above will most likely be trapped in an infinite loop(you may want to run the code multiple times to witness what I saw), as you can see in the main method I have called futures[i].cancel(true) for all tasks, I don't know why this is happening, this has been torturing me for more than a day.
Your help will be greatly appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我玩过你的代码,注意到线程的中断状态有时在套接字创建之前为 true,而在创建之后为 false。
我尝试中断一个线程并调用 Socket 构造函数,但之后线程始终保持中断状态。我也尝试取消线程池的关闭,问题仍然发生。
然后我尝试使用 5 个不同的 URI,而不是始终使用相同的 URI。而且这个问题从未发生过。
所以我写了这个简单的程序,表明线程池不是罪魁祸首,而是套接字:
事实上,当 5 个线程创建到同一主机和端口的套接字时,其中 4 个线程的中断状态被清除。
然后我尝试同步套接字创建(在单个锁上,但我猜你可能对每个主机/端口使用一个锁):
TADA...问题消失了。我会在 Oracle 中打开一个错误来表明该问题。
I've played with your code, and noticed that the thread's interrupt status is sometimes true before the socket creation, and false after.
I have tried interrupting a thread and calling the Socket constructor, and the thread always stays interrupted after. I also tried removing the shutdown of the threadpool, and the problem continued to happen.
Then I have tried using 5 different URIs, rather than always the same one. And the problem never happened.
So I wrote this simple program, showing that the thread pool is not the culprit, but the socket is:
And indeed, when 5 threads create a socket to the same host and port, 4 of them have their interrupt status cleared.
Then I tried to synchronize the socket creation (on a single lock, but I guess you might use one lock per host/port) :
and TADA... the problem disappeared. I would open a bug at Oracle to signal the problem.
我运行了你的代码,正如你所说,它并没有停止。
没有太多时间来调查它为什么会这样,但我发现将执行程序服务的线程声明为守护进程可以使问题消失:
如果我找到更好的解释,我会回来的。
I ran your code, and it didn't stop, as you said.
Didn't have much time to investigate why it behaves so, but I found out that declaring the executor service's threads as daemons made the problem go away :
I'll come back if I find a better explanation.
我认为当您尝试取消任务时任务没有开始的问题。我像这样添加了 Thread.sleep(100) :
一切都被取消了。
I think the problem that task are not started when you try to cancel them. I added
Thread.sleep(100)
like this:and everything was cancelled ok.