4

在我之前的一个问题上,我发布了:

我必须阅读几个非常大的 txt 文件,并且必须使用多个线程或单个线程来执行此操作,具体取决于用户输入。假设我有一个获取用户输入的 main 方法,并且用户请求一个线程并希望为该线程处理 20 个 txt 文件。我将如何做到这一点?请注意,以下不是我的代码或其设置,而只是“想法”。

例子:

int numFiles = 20;
int threads = 1;

 String[] list = new String[20];
 for(int i = 1; i < 21; i++){
   list[i] = "hello" + i + ".txt";//so the list is a hello1.txt, hello2.txt, ...,  hello20.txt
 }

 public void run(){
 //processes txt file
 }

总而言之,我将如何使用单个线程完成此操作?有20个线程?

一位用户建议使用 threadPools:

当用户指定要使用的线程数时,您将适当地配置池,提交一组文件读取作业,并让池对执行进行排序。在 Java 世界中,您将使用 Executors.newFixedThreadPool 工厂方法,并将每个作业作为 Callable 提交。这是 IBM 的一篇关于 Java 线程池的文章。

所以现在我有一个名为 sortAndMap(String x) 的方法,它接受一个 txt 文件名并进行处理,对于上面的例子,会有

Executors.newFixedThreadPool(numThreads);

如何将它与 threadPools 一起使用,以便我上面的示例可行?

4

3 回答 3

12

好的,请耐心等待,因为我需要解释一些事情。

首先,除非您有多个磁盘或者一个 SSD 磁盘,否则不建议使用多个线程从磁盘读取。关于这个主题的问题已经发布了很多,结论都是一样的:使用多个线程从单个机械磁盘中读取会损害性能而不是提高性能。

发生上述情况是因为磁盘的机械头需要不断寻找下一个要读取的位置。使用多个线程意味着当每个线程有机会运行时,它会将磁头引导到磁盘的不同部分,从而使其在磁盘区域之间的反弹效率低下。

处理多个文件的公认解决方案是拥有一个生产者(一个读取线程)-多个消费者(处理线程)系统。在这种情况下,理想的机制是一个线程池,一个线程充当生产者,并将任务放入池队列中供工人处理。

像这样的东西:

int numFiles = 20;
int threads = 4;

ExecutorService exec = Executors.newFixedThreadPool(threads);

for(int i = 0; i < numFiles; i++){
    String[] fileContents = // read current file;
    exec.submit(new ThreadTask(fileContents));
}

exec.shutdown();
exec.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
...

class ThreadTask implements Runnable {

   private String[] fileContents;

   public ThreadTask(String[] fileContents) {
        this.fileContents = fileContents;
   }

   public void run(){
      //processes txt file
   }
}
于 2012-05-01T11:43:57.657 回答
1

我将从阅读有关高级并发的本教程开始。我建议阅读整个并发教程,因为听起来你是多线程的新手。

于 2012-05-01T11:42:34.553 回答
1

因此,newFixedThreadPool()调用将返回ExecutorService的实例。您可以参考 JavaDoc,它非常全面并且包含一个可行的示例。您将需要一个submitinvokeAll多个Callables 来实现您的文件处理任务,从而为您提供多个Futures 作为回报。他们的get()方法将在完成后为您提供任务执行的结果(您必须自己编写该部分:))

于 2012-05-01T11:43:34.717 回答