Java 使用固定数量的线程和允许异常处理多线程数据
我正在用主线程逐行浏览大文本文件(5GB)。创建几个其他线程以同时格式化这些行 我已经使用Java 使用固定数量的线程和允许异常处理多线程数据,java,multithreading,Java,Multithreading,我正在用主线程逐行浏览大文本文件(5GB)。创建几个其他线程以同时格式化这些行 我已经使用Runnable类和Semaphore编写了一个解决方案,它控制运行的线程数量。不幸的是,Runnable不提供返回值或引发异常。如果在任何线程中抛出异常,我希望我的整个应用程序停止 我现在正试图使用可调用和未来,但内存不足 public class ProcessLine implements Callable<Boolean> { private final String inputLi
Runnable
类和Semaphore
编写了一个解决方案,它控制运行的线程数量。不幸的是,Runnable
不提供返回值或引发异常。如果在任何线程中抛出异常,我希望我的整个应用程序停止
我现在正试图使用可调用
和未来
,但内存不足
public class ProcessLine implements Callable<Boolean> {
private final String inputLine;
public ProcessLine(String inputLine) {
this.inputLine = inputLine;
}
@Override
public Boolean call() throws Exception {
formatLine(inputLine); // huge method which can throw exceptions
return true;
}
}
这里的第一个问题是,所有Future
对象都收集在futures
列表中。毫不奇怪,当我每行有一个项目时,我的内存就用完了
第二个问题是:在处理文本文件的最后,我将使用get()
方法检查所有Future
项。我甚至没有注意到第一行是否抛出了异常
请帮助我找出解决方法。您可以通过创建自定义
ThreadPoolExecutor
来限制挂起任务的数量,方法如下:
ExecutorService executor = new ThreadPoolExecutor(
threads,
threads,
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(WORK_QUEUE_SIZE));
因此,存储任务处理的所有结果(对每个任务使用
Future
)占用了太多内存,但您可以单独对这些结果进行进一步处理,而不需要完整的集合(对吧?)
您可以考虑将每个任务传递到另一个工作队列,以供另一线程池处理。如果第二个工作队列具有固定大小,则保证内存使用是有限的。这是管道和过滤器设计模式的变体。它有一个很好的特性,即如果第二阶段的处理太慢,最终第二个工作队列将被填满,导致第一个线程池的线程阻塞。然后,第二个线程池的线程可以使用更多的CPU时间。也就是说,它以最大化吞吐量的方式在线程池之间自动共享CPU时间
如果开始处理(当处理的行数等于第二个队列的大小时),则保证在有限时间内检查处理文件第一行的结果,该结果可用于满足您及时处理问题的要求我已经将这种设计用于一个程序,该程序下载数据并将其写入文件,以防止程序保留太多等待处理的数据 我尝试了其他几种解决方案,但我认为我自己找到了最适合我的
public static final ThreadStatus threadStatus = new ThreadStatus();
public static class ThreadStatus {
private Exception exception = null;
public void setException(Exception exception) {
if(exception == null) {
return;
}
this.exception = exception;
}
public Exception getException() {
return exception;
}
public boolean exceptionThrown() {
return exception != null;
}
}
然后在线程的run()
方法中:
catch(Exception e) {
Main.threadStatus.setException(e);
}
在循环中遍历所有行:
ProcessLine processLine = new ProcessLine(inputLine);
Future f = executor.submit(processLine);
futures.add(f);
if(Main.threadStatus.exceptionThrown()) {
throw Main.threadStatus.getException();
}
感谢所有帮助我的人。如果我的文本文件超过了
工作队列大小中允许的整数.MAX\u值
,会发生什么?那么未来的问题呢?不,不,工作队列的大小决定了你在任何时间点可以拥有多少个待定的未来。如果愿意,可以将1放在那里。已针对第二个问题更新。如果我在executor.submit()之后立即调用.get()
,我会立即知道格式化线程是否引发异常。但是我的主线程必须等待格式线程中的计算完成。这会阻止线程同时运行,并使多线程变得毫无意义。对吗?我总是使用4个格式的线程,现在我的应用程序花费的时间是原来的4倍。那么,难道你不能让处理行处理终止逻辑吗?或者将结果放入另一个由结果处理器处理的队列中。
catch(Exception e) {
Main.threadStatus.setException(e);
}
if(Main.threadStatus.exceptionThrown()) {
throw Main.threadStatus.getException();
}