我将Callables提交给ExecutorCompletionService,似乎submit()
方法在提交Callables时不会阻止代码。这是我的代码:
ExecutorService executor = Executors.newFixedThreadPool(30);
BlockingQueue<Future<Data>> completionQueue = new LinkedBlockingQueue();
ExecutorCompletionService<Data> completionService = new ExecutorCompletionService<Data>(executor, completionQueue);
while(receivingPackets) {
Callable<Data> splitPacketCallable = new SplitPacket(packetString);
completionService.submit(splitPacketCallable);
try {
// Allow submit to finish
TimeUnit.MILLISECONDS.sleep(50);
} catch (InterruptedException ex) {
System.out.println("Something went wrong with sleeping");
}
try {
Future<Data> dataFuture = completionService.poll();
if (dataFuture != null) {
Data data = dataFuture.get();
fileWriter.writeLine(data.toString());
}
} catch (InterruptedException ex) {
System.out.println("Error from poll: " + ex.toString());
} catch (ExecutionException ex) {
System.out.println("Error from get: " + ex.toString());
}
}
// Finish any remaining threads
while (!completionQueue.isEmpty()) {
try {
Future<Data> dataFuture = completionService.take();
Data data = dataFuture.get();
fileWriter.writeLine(data.toString());
} catch (InterruptedException ex) {
System.out.println("Error from take: " + ex.toString());
} catch (ExecutionException ex) {
System.out.println("Error from get: " + ex.toString());
}
}
fileWriter.close();
executor.shutdown();
有几点需要注意:
Data
是一个以特殊格式存储数据的类。 SplitPacket
是一个实现Callable的类,它接收已到达的String并将其拆分为块以保存在Data
中。 fileWriter
及其方法writeLine
是一个Runnable类,它将异步写入多个线程中的单个文件。
如果我在for循环中玩睡眠,我会在输出文件中开始获得不一致的结果。如果我每次提交Callable都会睡50码,一切都很完美。但是,如果我以低值(例如0-5毫秒)提交,我开始在输出中删除线程。对我而言,这意味着submit()
的ExecutorCompletionService
方法不会阻止。但是,因为阻止提交的callable似乎很重要,我也假设我只是实现了这个错误。
就我而言,我不知道会有多少数据包进入,因此我需要能够不断向执行者添加Callables。我用for循环而不是while循环尝试了这个,这样我就可以发送给定数量的数据包并查看它们是否在另一端打印,如果我在提交后有延迟,我只能让它们通过
有没有办法解决这个问题而不会增加hack-y延迟?
答案 0 :(得分:0)
如果查看ExecutorCompletionService
的来源,您会看到在任务标记为已完成后,期货将被添加到completionQueue
。
private class QueueingFuture extends FutureTask<Void> {
QueueingFuture(RunnableFuture<V> task) {
super(task, null);
this.task = task;
}
protected void done() { completionQueue.add(task); }
private final Future<V> task;
}
您可能有一个空队列但仍在运行任务。 你能做的最简单的事情就是计算任务。
int count = 0;
while(receivingPackets) {
...
completionService.submit(splitPacketCallable);
++count;
...
try {
Future<Data> dataFuture = completionService.poll();
if (dataFuture != null) {
--count;
...
}
...
}
// Finish any remaining threads
while (count-- > 0) {
...
}