如何在没有stop()方法的情况下停止线程?

问题描述:

我有关于Java线程的问题。这是我的场景:如何在没有stop()方法的情况下停止线程?

我有一个线程调用可能需要一段时间的方法。线程保持自己的方法,直到我得到结果。如果我以同样的方式向该方法发送另一个请求,则现在有两个线程正在运行(只要第一个线程没有返回结果)。但我想优先考虑最后一个线程,不想从先前启动的线程获取结果。那么当我没有停止方法时,我怎么能摆脱先前的线程呢?

+0

我真的不明白,如果你想优先考虑线程或真的停止线程!? – 2010-07-13 16:37:38

+0

不想优先考虑这些。但是2避免以前的所有... – bandit 2010-07-13 21:28:42

你可以interrupt一个线程,它的执行链大部分时间都会抛出一个InterruptedException异常(参见the documentation中的特殊情况)。

的标准设计模式是可以被设置为阻止它的线程使用本地变量:

public class MyThread extends Thread { 
    private volatile boolean running = true; 

    public void stop() { 
     running = false; 
    } 

    public void run() { 
     while (running) { 
     // do your things 
     }  
    } 
} 

这种方式可以greacefully终止线程,也就是未抛出InterruptedException

+1

如果* things *在循环中或可以从'run()'方法中断,那么确实会更干净。另外,你可以在'running'中添加一个'volatile'修饰符。 – 2010-07-13 16:44:06

+0

@streetpc:谢谢,确实忘了'volatile'关键字。通常长时间运行的“东西”已经在循环中 - 所以你可以合并循环来考虑运行状态。 – 2010-07-13 16:49:07

+0

小东西;它是布尔,而不是布尔,在Java – 2010-07-13 16:55:07

最好的方法真的取决于该方法的作用。如果它在等待什么,机会是interrupt将导致你处理并干净退出的InterruptedException。如果它做一些忙,也不会:

class Scratchpad { 
    public static void main(String[] a) { 
     Thread t = new Thread(new Runnable() { 
      public void run() {doWork();} 
     }); 
     t.start(); 

     try { 
      Thread.sleep(50); 
     } catch (InterruptedException ie) {} 

     t.interrupt(); 
    } 

    private static void doWork() { 
     for (long i = 1; i != 0; i *=5); 
    } 
} 

在上述情况下,唯一可行的解​​决方案确实是一个标志变量来打破循环的取消,阿拉@inflagranti早。

事件驱动体系结构的另一种选择是poison-pill:如果你的方法正在等待一个新项目的阻塞队列,那么你可以有一个全局常量项目,称为“毒药”取出的),你杀线程:

try { 
    while(true) { 
     SomeType next = queue.take(); 
     if (next == POISON_PILL) { 
      return; 
     } 
     consume(next); 
    } 
} catch //... 

编辑

看起来你真正想要的是一个executor service。当您将作业提交给执行者服务时,您会收到Future,您可以使用它来跟踪结果并取消作业。

+0

实际上,线程等待twitter的搜索结果,你认为中断会工作吗? – bandit 2010-07-13 17:04:29

如果您只是想减缓其他线程,而不是有它的出口,你可以采取一些其他办法...

一两件事,就像离开你可以去优先变量,当设置时,让你的线程在每次迭代中睡100ms。这会在你的其他线程搜索时有效地阻止它,然后当你重新排列优先级时,它会回到全速。

但是,这是有点马虎。既然你只想要一件事情正在运行,但你希望在优先级完成时记得处理其他事务,那么你可能想用一个重复调用的.process()方法将你的处理放到一个类中。当您希望暂停处理该请求时,您只需停止在该对象上调用.process一段时间。

通过这种方式,你可以实现一堆这样的对象,你的线程只会执行stack.peek()。process();每一次迭代,所以将新的更重要的任务推送到堆栈上会自动停止以前的任何操作。

这导致了更为灵活的调度 - 例如,如果没有任何东西可以让process()返回false,那么您的调度程序可能会转到堆栈中的下一个项目并尝试其“进程()方法,在单线程中给你一些严肃的多任务处理能力,而不会增加资源负担(网络,我猜)

Thread有一个setPriority(int)方法。您可以设置第一个线程的优先级是这样的:

Thread t = new Thread(yourRunnable); 
t.start(); 
t.setPriority(Thread.MIN_PRIORITY); // The range goes from 1 to 10, I think 

但这不会杀你的线程。如果你只有两个线程使用你的runnable,那么这是一个很好的解决方案。但是,如果您在循环中创建线程,并且始终将最后一个线程的优先级设置为最小,则会获得大量线程。
如果这是应用程序将要执行的操作,请查看ThreadPool。这不是Java API中的现有类。你将自己创建一个。
ThreadPool是另一个Thread,它以您想要的方式管理您的所有其他Threads。您可以设置最大数量的正在运行的线程。在该ThreadPool中,您可以实现一个自动管理线程优先级的系统。例如:您可以让较旧的线程获得更多优先级,以便您可以正确结束它们。

所以,如果你知道如何使用ThreadPool,它可以是非常有趣的。

根据java.lang.Thread API,您应该使用interrupt()方法并检查isInterrupted()标志,而您正在做一些耗时的可取消操作。这种方法可以处理不同种类的“等待情况”:
1.在调用interrupt()方法
后,wait(),join()和sleep()方法将抛出InterruptedExcetion 2.如果线程被java.nio.channels.Selector阻塞,它将完成选择器操作
3.如果您在等待I/O线程将接收到ClosedByInterruptException,但在这种情况下,您的I/O设施必须实现InterruptibleChannel接口。

如果无法以通用方式中断此操作,则可以简单地放弃上一个线程并从新线程中获取结果。你可以通过java.util.concurrent.Futurejava.util.concurrent.ExecutorService来完成。

Cosider下面的代码片段:这里

public class RequestService<Result> { 

private ExecutorService executor = Executors.newFixedThreadPool(3); 

private Future<Result> result; 

    public Future<Result> doRequest(){ 
    if(result !=null){ 
     result.cancel(true); 
    } 
    result = executor.submit(new Callable<Result>() { 
     public Result call() throws Exception { 
      // do your long-running service call here 
     } 
    }); 
    return result; 
    } 

} 

Future对象代表服务调用的结果。如果再次调用doRequest方法,它会尝试取消先前的任务,然后尝试提交新的请求。就线程池包含多个线程而言,您不必等到先前的请求被取消。新请求立即提交,方法返回新的请求结果。