可能重复: How do you kill a thread in Java?
我需要通过向线程发送中断信号来停止执行一些大任务。我正在使用java.util.concurrent。*中的大多数API。我的任务是发送到线程并执行。此任务来自客户端,因此我无法控制该代码。
任务类似于:
public class Task1 extends Thread {
public void run() {
while(true){
if(Thread.interrupted()){
return;
}
for(int i=0; i<Integer.MAX_VALUE; i++){
System.out.println("I am task 1 " + i);
}
}
}
};
我希望在接收到中断信号时基本上停止循环for-loop(请注意我不能将Thread.interrputed()逻辑放在for循环中,因为它来自客户端。)我有另一个类使用Executor执行此任务。
public class ConcurrentTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
ConcurrentTest test = new ConcurrentTest();
ExecutorService executorService = Executors.newFixedThreadPool(2);
Task1 task1 = new Task1();
Future<?> runningTask1 = executorService.submit(task1);
Task2 task2 = new Task2();
Future<?> runningTask2 = executorService.submit(task2);
//Stop First task after 5 second
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
runningTask1.cancel(Boolean.TRUE);
System.out.println("runningTask1.isDone is " + runningTask1.isDone());
System.out.println("runningTask1.isCancelled is " + runningTask1.isCancelled());
//Stop Second task after 10 second
try{
TimeUnit.SECONDS.sleep(3);
}catch(InterruptedException e){
e.printStackTrace();
}
runningTask2.cancel(Boolean.TRUE);
System.out.println("runningTask2.isDone is " + runningTask2.isDone());
System.out.println("runningTask2.isCancelled is " + runningTask2.isCancelled());
}
}
任务2是:
public class Task2 extends Thread{
public void run() {
while(true){
if(Thread.interrupted()){
return;
}
System.out.println("I am task 2");
}
}
};
Task2是互为的,但Task1永远不会被中断并继续在for循环中执行。我不能在客户端代码中添加任何逻辑(类似于for循环)。我需要SO社区的帮助来解决这个问题。感谢。
答案 0 :(得分:3)
唯一防弹解决方案是在隔离区中运行客户端提供的代码。隔离本质上是Java应用程序可以创建,管理和通信的私有虚拟机。特别是,父应用程序可以安全地杀死隔离及其所有线程。
参考:JSR-000121 Application Isolation API Specification - Final Release
问题是找到支持隔离的JVM。
答案 1 :(得分:2)
重新阅读您的问题并意识到您无法控制任务代码。
task1没有中断的原因是interrupt()方法实际上并没有中断任何东西,只会在线程等待某个锁或休眠时导致线程中断,否则它实际上不会除了设置状态之外的任何事情。
为您杀死task1的唯一方法是使用Thread.stop()方法。 但请注意,它可能非常危险,并使您的系统不稳定。 查看更多here。
答案 2 :(得分:2)
您可以使用“停止”标志和包装类来终止您自己的任务以及客户端为您提供的任务。
public class MyTask implements Runnable {
private TaskController taskControl;
@Override
public void run() {
if(taskControl.abort()) {
return;
}
// Task logic ...
}
}
// Construct on main thread, call "run()" on a dedicated background thread.
public class TaskController implements Runnable {
private AtomicBoolean terminate = new AtomicBoolean(false);
private ThreadPoolExecutor yourTaskThreadPool;
private ThreadPoolExecutor otherTaskThreadPool;
@Override
public void run() {
// Your task construction, dispatch logic. Use your own thread pool
// Run the tasks you don't control in THEIR own pool
if(terminate.get()) {
otherTaskThreadPool.shutdown();
}
otherTaskThreadPool.execute( clientsTask ); // e.g. "task1"
}
public void AbortAllTasks() {
terminate.set(true);
}
public boolean abort() {
return terminate.get();
}
}
您的任务可以将控制器(“this”指针)作为构造参数,并检查其run()
中的终止标志。这允许您通过调用TaskController.AbortAllTasks()
来异步杀死所有这些。对于您无法控制的任务,您可以将自己的中断逻辑放在TaskController.run()
中。
答案 3 :(得分:1)
中断实际上是一种合作取消机制,而不是先发制人。它需要从任务的合作做出优雅的取消。如果任务是不可中断的(即不通过检查中断状态或响应InterruptedException而中止其操作),则无法取消任务。提供中断是微不足道的;这真的是任务如何响应它。
一种可能的解决方案可能是通过动态检测等方法将代码注入任务。但是,即使这不是一个肯定的赌注,如果任务使用while循环,则需要在while循环中注入代码。
答案 4 :(得分:1)
我会提供一种机制,允许客户端代码协同处理停止信号。如果客户端代码处理信号,那么您的应用和客户同意它可以及时停止。否则,当代码返回到interrupted()检查时,您将中断该线程。我的观点是你应该要求客户代码合作而不是盲目地打断它。
答案 5 :(得分:0)
在while循环内和for循环中检查两次中断。
while(true){
if(Thread.interrupted()){
return;
}
for(int i=0; i<Integer.MAX_VALUE; i++){
if(Thread.interrupted()){
return;
}
System.out.println("I am task 1 " + i);
}
}
答案 6 :(得分:0)
如果其他人在工作线程中提供代码(作为jar?),他们会根据工作的一部分调用您的代码吗?您可以将检查中断的函数放入他们调用的函数中,然后抛出一个未经检查的异常,我们希望它将终止该线程。
// Called from the worker thread code that someone else writes,
// hopefully often so that we notice when we're interrupted.
public void doSomething() {
if (Thread.interrupted()) {
throw new MyRuntimeException();
}
// do what this method is meant to do ...
}
小心警告编写该代码的开发人员:请参阅this article describing some of the problems that can arise。
因此,简而言之,如果您不编写该代码,最好尝试让任何人检查Thread.interrupted(),以便他们可以干净地退出。
答案 7 :(得分:0)
一种停止线程的简单方法是为每个线程定义一些停止标志,然后定期检查该标志。
例如:
class MyTask implements Runnable {
private AtomicBoolean stopflag = new AtomicBoolean();
public void stop() {
stopflag.set(true);
}
public void run() {
while(true) {
if(!stopflag.get())
/// do some work
else
return; // get out
}
}
}
答案 8 :(得分:0)
如果不在for语句本身中进行更改,则无法进行此操作。由于Sun贬低了立即线程暂停的方法。他们有他们的理由。 (see here)唯一的方法是在循环中使用布尔值,或者,如果线程在for循环内等待,则可以捕获由Thread.interuppt()抛出的InterruptedException