【问题标题】:How can I stop threads created with an anonymous class?如何停止使用匿名类创建的线程?
【发布时间】:2011-12-11 13:38:38
【问题描述】:
在我的程序中,我有许多线程处于工作状态,在方法 run 中启动或通过从 run 调用其他方法启动。有什么方法可以停止这些线程?
线程开始为:
Runnable r = new Runnable() {
@Override
public void run() {
// do something...
}
};
new Thread(r,"Thread_1").start();
另一个可能是这样的:
Runnable r = new Runnable() {
@Override
public void run() {
startThread(); // another method called
}
};
new Thread(r,"Thread_2").start();
停止thread_1和thread_2的方法是什么?
更新
我想要的是,当我点击一个按钮时,deactivate 后面工作的 3-4 个线程应该被停用,以便用户可以通过再次分配任务来再次启动这些线程。
【问题讨论】:
标签:
java
multithreading
anonymous-types
【解决方案1】:
Thread.stop() 非常危险,强烈建议您避免使用它,原因在 javadoc 中说明。
尝试将消息传递到Runnable,可能使用如下方式:
final AtomicBoolean terminate = new AtomicBoolean(false);
Runnable r = new Runnable() {
@Override
public void run() {
while (!terminate.get()) {
// do something...
}
}
};
new Thread(r,"Thread_1").start();
// some time later...
terminate.set(true);
您必须想办法确定变量的范围,以允许在您的设置下编译。或者,使用您的接口扩展Runnable,该接口具有cancel() 方法(或其他方法),您的匿名类必须实现该方法,它使用循环检查标志执行类似的操作。
interface CancellableRunnable extends Runnable {
void cancel();
}
CancellableRunnable r = new CancellableRunnable() {
private volatile terminate = false;
@Override
public void run() {
while (!terminate) {
// do something...
}
}
@Override
public void cancel() {
terminate = true;
}
}
new Thread(r,"Thread_1").start();
// some time later...
r.cancel();
【解决方案2】:
Thread 类在 java 1.0 中引入了 stop() 方法,在 java 1.1 中不推荐使用。此方法仍然有效并杀死线程。因此,您可以根据需要停止所有线程。
但这是非常不推荐的。原因在Thread.stop() 的javadoc 中有描述。因此,最好的解决方案是修复线程的实现以使它们正确退出。但如果不可能(例如,如果这不是您的代码)并且您仍然非常需要这个,请使用 Thread.stop()。
【解决方案3】:
设置标志并让线程定期检查标志以驱动线程中断的问题是,如果您的线程正在调用长时间运行的 API 方法或阻塞方法,例如完整 BlockingQueue 上的 put 方法,该怎么办?那将永远不会出队,因为要使其出队的线程已被关闭,或者阻止从同样永远不会被写入的套接字读取?在所有这些情况下,这些长时间运行的调用都不会停止检查您的标志,并且您的应用程序可能会挂起。
中断线程的正确方法是在该线程实例上执行 Thread.interrupt() 方法,并且在正在运行的线程本身中,您应该定期检查 Thread.currentThread().isInterrupted() 以确定线程是否应该被中断,当然要捕获 InterruptedException 并在它被抛出时执行有序的关闭。
这种方法的优点是,如果您的线程正在调用一个长时间运行的方法,希望该方法也会定期检查 Thread.currentThread().isInterrupted(),并通过执行有序的操作来响应中断请求关闭,然后传播 InterruptedException。例如,BlockingQueue.put 确实会检测到 Thread.interrupt() 发出的中断请求。套接字不会检测到中断请求,但会响应关闭套接字,这可以在线程重写的 interrupt() 方法中完成。
由于确实无法在匿名线程上调用 interrupt() 方法,因此您可能不应该将它们用于长时间运行的任务。
我推荐阅读“Java 并发实践”。这是一本很棒的书,第 7 章“取消和关闭”专门讨论这类事情。它比我能解释的要好得多。
【解决方案4】:
如果要强制中止它们,可以调用stop() 方法(不推荐)。只要确保您没有打开文件、进行套接字 I/O、使用锁等。
更好的方法是在运行中使用 while 循环测试标志:
public void run() {
while(!stop) {
// work
}
}
当您希望线程停止时,将stop 设置为true。别忘了volatile。
【解决方案5】:
据我了解,您想知道如何检测特定匿名线程并停止它。
您可以尝试getCurrentThread() 方法来检测线程。虽然使用stop() 并不安全,但已被弃用。
Thread thread = Thread.getCurrentThread();
if(thread.getName() == "Thread_1" || thread.getName() == "Thread_2")
{
thread.stop();
}