我写了以下多线程程序。我想取消所有线程,如果其中一个线程发回false作为返回。但是,虽然我通过取消单个任务取消了该线程。它不起作用。我需要做些什么改变来取消线程?
我写了以下多线程程序。我想取消所有线程,如果其中一个线程发回false作为返回。但是,虽然我通过取消单个任务取消了该线程。它不起作用。我需要做些什么改变来取消线程?
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Callable;
public class BeamWorkerThread implements Callable<Boolean> {
private List<BeamData> beamData;
private String threadId;
public BeamScallopingWorkerThread(
List<BeamData> beamData, String threadId) {
super();
this.beamData = beamData;
this.threadId = threadId;
}
@Override
public Boolean call() throws Exception {
Boolean result = true;
DataValidator validator = new DataValidator();
Iterator<BeamScallopingData> it = beamData.iterator();
BeamData data = null;
while(it.hasNext()){
data = it.next();
if(!validator.validateDensity(data.getBin_ll_lat(), data.getBin_ll_lon(), data.getBin_ur_lat(), data.getBin_ur_lon())){
result = false;
break;
}
}
return result;
}
}
ExecutorService threadPool = Executors.newFixedThreadPool(100);
List<Future<Boolean>> results = new ArrayList<Future<Boolean>>();
long count = 0;
final long RowLimt = 10000;
long threadCount = 1;
while ((beamData = csvReader.read(
BeamData.class, headers1, processors)) != null) {
if (count == 0) {
beamDataList = new ArrayList<BeamData>();
}
beamDataList.add(beamData);
count++;
if (count == RowLimt) {
results.add(threadPool
.submit(new BeamWorkerThread(
beamDataList, "thread:"
+ (threadCount++))));
count = 0;
}
}
results.add(threadPool.submit(new BeamWorkerThread(
beamDataList, "thread:" + (threadCount++))));
System.out.println("Number of threads" + threadCount);
for (Future<Boolean> fs : results)
try {
if(fs.get() == false){
System.out.println("Thread is false");
for(Future<Boolean> fs1 : results){
fs1.cancel(true);
}
}
} catch(CancellationException e){
} catch (InterruptedException e) {
} catch (ExecutionException e) {
} finally {
threadPool.shutdownNow();
}
}
我的评论
感谢大家的投入,我对回应感到不知所措。我知道,实施良好的线程会将应用程序置于高位,并且意味着错误的实现会使应用程序陷入困境。我同意我有想法,但我没有其他选择。我有一个1000万以上的记录因此我将有内存约束和时间限制。我需要解决这两个问题。因此,不是吞下整个数据,而是将其分成块,如果一个数据无效,我也不想浪费时间处理剩余的数百万个数据。我发现@Mark Peters的建议是一种选择。做出相应的更改我的意思是添加标志来中断任务,我很困惑未来的列表如何工作。我理解的是,一旦所有线程返回其值,循环遍历未来列表的每个字段。在这种情况下,无法从主列表中间取消所有任务。我需要将对象的引用传递给每个线程。如果一个线程使用线程参考找到无效数据,则调用每个线程的cancel mathod来设置中断标志。
while(it.hasNext() && !cancelled) {
if(!validate){
// loop through each thread reference and call Cancel method
}
}
答案 0 :(得分:7)
如果您尝试取消所有剩余任务,那么如果您的代码未被仔细编写为可中断,则会失败。究竟需要的是StackOverflow的一个答案。一些指导原则:
InterruptedException
。让它发生破坏任务; Thread.interrupted()
检查并做出适当的反应。编写可中断代码通常不是初学者的东西,所以要小心。
答案 1 :(得分:2)
取消Future
不会中断正在运行的代码。它主要用于防止任务首先运行。
虽然您可以提供true
作为参数,它将中断运行任务的线程,但只有在线程被抛出InterruptedException
的代码中被阻止时才会生效。除此之外,没有任何内容隐式检查线程的interrupted
状态。
在你的情况下,没有阻止;忙碌的工作需要时间。一种选择是在循环的每个阶段都检查一个volatile布尔值:
public class BeamWorkerThread implements Callable<Boolean> {
private volatile boolean cancelled = false;
@Override
public Boolean call() throws Exception {
//...
while(it.hasNext() && !cancelled) {
//...
}
}
public void cancel() {
cancelled = true;
}
}
然后,您将保留对BeamWorkerThread
个对象的引用,并在其上调用cancel()
以抢占其执行。
Marko提到上面的cancelled
标志实际上是在重新发明Thread.interrupted()
。这是一个有效的批评。这就是为什么我不喜欢在这种情况下使用中断。
<强> 1。它取决于某些线程配置。
如果您的任务代表可以提交给执行者或直接调用的可取消代码段,则使用Thread.interrupt()
取消一般情况下的执行假定代码接收中断将是应该知道如何干净地取消任务的代码。
在这种情况下可能是这样,但我们只知道这一点,因为我们知道取消和任务内部如何工作。但想象一下我们有这样的事情:
Thread.interrupt()
换句话说,我觉得interrupt()
太过全局的机制了。像任何共享的全球状态一样,它对所有参与者做出假设。这就是我的意思,说使用interrupt()
公开/耦合有关运行上下文的详细信息。通过将其封装在仅适用于该任务实例的cancel()
方法中,可以消除该全局状态。
<强> 2。它并不总是一种选择。
这里的经典示例是InputStream
。如果您有一项阻止从InputStream
阅读的任务,interrupt()
将无法取消阻止它。取消阻止它的唯一方法是手动关闭流,这是在cancel()
方法中为任务本身最好的方法。有一种方法可以取消任务(例如Cancellable
),无论其实现如何,对我来说都是理想的。
答案 2 :(得分:1)
使用ExecutorService.shutdownNow()
方法。它将阻止执行程序接受更多提交并返回正在执行的任务的Future
个对象,您可以调用cancel(true)
来中断执行。当然,您将不得不丢弃此执行程序,因为它无法重新启动。
如果线程没有在监视器上等待(没有被中断阻塞),并且如果吞下将在其中引发的InterruptedException,cancel()
方法可能不会立即终止执行这种情况。