我对Java线程有疑问。这是我的情景:
我有一个线程调用一个可能需要的方法。线程保持自己的方法,直到我得到结果。如果我以相同的方式向该方法发送另一个请求,现在有两个线程在运行(前提是第一个没有返回结果)。但我想优先考虑最后一个线程,并且不希望从先前启动的线程中获得结果。那么当我没有停止方法时,我怎么能摆脱早期的线程?
答案 0 :(得分:5)
标准设计模式是在线程中使用局部变量,可以将其设置为停止它:
public class MyThread extends Thread {
private volatile boolean running = true;
public void stop() {
running = false;
}
public void run() {
while (running) {
// do your things
}
}
}
这样你就可以毫不费力地终止线程,即不抛出InterruptedException
。
答案 1 :(得分:4)
最好的方法实际上取决于该方法的作用。如果它等待某事,很可能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 );
}
}
在上面的例子中,唯一可行的解决方案实际上是一个标志变量,可以在取消的早期突破循环,ala @inflagranti。
事件驱动架构的另一个选择是poison-pill:如果你的方法正在等待一个新项目的阻塞队列,那么你可以有一个名为“poison-pill”的全局常量项,当它消耗时(出列)你杀了线程:
try {
while(true) {
SomeType next = queue.take();
if ( next == POISON_PILL ) {
return;
}
consume(next);
}
} catch //...
编辑:
看起来你真正想要的是executor service。当您向执行者服务提交作业时,您将获得Future
,您可以使用该{{3}}来跟踪结果并取消作业。
答案 2 :(得分:2)
你可以interrupt一个Thread,它的执行链大部分时间都会抛出InterruptedException(参见the documentation中的特殊情况)。
答案 3 :(得分:0)
如果您只是想放慢其他线程的速度并且不让它退出,您可以采取其他方法......
首先,就像退出一样,你可以有一个去优先级变量,当设置它时,你的线程在每次迭代时都会休眠100ms。当你的其他线程被搜索时,这将有效地阻止它,然后当你重新确定它的优先级时,它将恢复到全速。
然而,这有点草率。因为你只想要运行一个东西但是你想让它记住在完成优先级时处理其他东西,你可能希望将处理放入一个带有重复调用的.process()方法的类中。当您希望暂停处理该请求时,您只需停止在该对象上调用.process一段时间。
通过这种方式,你可以实现一堆这样的对象,你的线程就会执行stack.peek()。process();每次迭代,所以将一个新的,更重要的任务推送到堆栈上会自动停止任何先前的任务。
这会导致更灵活的调度 - 例如,如果没有任何内容可以执行,那么您可以让process()返回false,此时调度程序可能会转到堆栈上的下一个项目并尝试其'进程( )方法,在单个线程中为您提供一些严重的多任务处理能力,而不会使您的资源负担过重(网络,我猜)
答案 4 :(得分:0)
setPriority(int)
有一种Thread
方法。您可以将第一个线程的优先级设置为:
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,它会非常有趣。
答案 5 :(得分:0)
根据java.lang.Thread
API,您应该使用interrupt()
方法并在执行一些耗时的可取消操作时检查isInterrupted()
标志。这种方法可以处理不同类型的“等待情况”:
1.调用InterruptedExcetion
方法后,wait(),join()和sleep()方法将抛出interrupt()
2.如果线程被java.nio.channels.Selector
阻止,它将完成选择器操作
3.如果您正在等待I / O线程将收到ClosedByInterruptException
,但在这种情况下,您的I / O工具必须实现InterruptibleChannel
接口。
如果无法以通用方式中断此操作,则可以简单地放弃先前的线程并从新线程获取结果。您可以通过java.util.concurrent.Future
和java.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
方法,它会尝试取消上一个任务,然后尝试提交新请求。至于线程池包含多个线程,您不必等到上一个请求被取消。立即提交新请求,方法会返回新的请求结果。