关于我之前的一个问题,我发布了:
我必须读取几个非常大的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中使用它,以便上面的示例可行?
答案 0 :(得分: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
}
}
答案 1 :(得分:1)
我首先要阅读关于高级并发的tutorial。我建议阅读整个concurrency tutorial因为听起来你是多线程的新手。
答案 2 :(得分:1)
因此,newFixedThreadPool()
调用将返回ExecutorService的实例。您可以引用JavaDoc,它非常全面并且包含一个可行的示例。您需要submit
或invokeAll
一些Callable
来实现您的文件处理任务,并为您提供一些Future
作为回报。他们的get()
方法将在完成后为您提供任务执行的结果(您必须自己编写该部分:))