在JAVA中的线程之间统一分割目录中的文件

时间:2012-12-26 05:30:57

标签: java multithreading file-io

我在目录中有一个变量文件列表,我在Java中有不同的线程来处理它们。线程可变,具体取决于当前处理器

int numberOfThreads=Runtime.getRuntime().availableProcessors();

File[] inputFilesArr=currentDirectory.listFiles();

如何跨线程统一拆分文件?如果我做简单的数学运算

int filesPerThread=inputFilesArr.length/numberOfThreads

如果inputFilesArr.lengthnumberOfThreads不能完全相互整除,我可能会遗漏一些文件。这样做的有效方法是什么,以便所有线程的分区和负载均匀?

5 个答案:

答案 0 :(得分:2)

以下是对此问题的另一种看法:

  1. 使用java的ThreaPoolExecutorHere is an example
  2. 它的工作原理是线程池您不需要在每次需要时创建线程,但在开始时创建指定数量的线程并使用池中的线程
  3. 想法是将目录中每个文件的处理视为独立任务,由每个线程执行。
  4. 现在,当您循环向执行程序提交所有任务时(这确保没有遗漏任何文件)。
  5. Executor实际上会将所有这些任务添加到队列,同时它将从线程池中获取线程,为它们分配任务,直到所有线程很忙
  6. 等待直到线程可用。因此,配置线程池大小至关重要。您可以拥有与文件数量相同的线程数或者少于该数量的线程数。
  7. 这里我做了一个假设,每个要处理的文件是相互独立的,并且它不需要由一个线程处理某一堆文件。

答案 1 :(得分:1)

您可以使用循环算法进行最佳分配。这是伪代码:

ProcessThread t[] = new ProcessThread[Number of Cores];
int i = 0;
foreach(File f in files)
{
    t[i++ % t.length].queueForProcessing(f);
}

foreach(Thread tt in t)
{
    tt.join();
}

答案 2 :(得分:1)

Producer Consumer模式将优雅地解决这个问题。让一个生产者(主线程)将所有文件放在绑定的阻塞队列中(参见BlockingQueue)。然后让一些工作线程从队列中获取文件并进行处理。

工作(而不是文件)将统一分布在线程上,因为处理完一个文件的线程要求下一个要处理的文件。这样可以避免一个线程只被分配大型文件进行处理的问题,而其他线程只能处理小文件。

答案 3 :(得分:0)

您可以尝试获取每个线程的文件范围(inputFilesArr的开始和结束索引):

if (inputFilesArr.length < numberOfThreads)
        numberOfThreads = inputFilesArr.length;

int[][] filesRangePerThread = getFilesRangePerThread(inputFilesArr.length, numberOfThreads);

private static int[][] getFilesRangePerThread(int filesCount, int threadsCount)
{
    int[][] filesRangePerThread = new int[threadsCount][2];

    if (threadsCount > 1)
    {
        float odtRangeIncrementFactor = (float) filesCount / threadsCount;
        float lastEndIndexSet = odtRangeIncrementFactor - 1;
        int rangeStartIndex = 0;
        int rangeEndIndex = Math.round(lastEndIndexSet);

        filesRangePerThread[0] = new int[] { rangeStartIndex, rangeEndIndex };

        for (int processCounter = 1; processCounter < threadsCount; processCounter++)
        {
            rangeStartIndex = rangeEndIndex + 1;
            lastEndIndexSet += odtRangeIncrementFactor;
            rangeEndIndex = Math.round(lastEndIndexSet);
            filesRangePerThread[processCounter] = new int[] { rangeStartIndex, rangeEndIndex };
        }
    }
    else
    {
        filesRangePerThread[0] = new int[] { 0, filesCount - 1 };
    }

    return filesRangePerThread;
}

答案 4 :(得分:0)

如果你正在处理I / O,即使有一个处理器,多个线程也可以并行工作,因为当一个线程正在等待read(byte [])时,处理器可以运行另一个线程。

无论如何,这是我的解决方案

int nThreads = 2;
File[] files = new File[9];
int filesPerThread = files.length / nThreads;

class Task extends Thread {
    List<File> list = new ArrayList<>();
                // implement run here
}

Task task = new Task();
List<Task> tasks = new ArrayList<>();
tasks.add(task);
for (int i = 0; i < files.length; i++) {
    if (task.list.size() == filesPerThread && files.length - i >= filesPerThread) {
        task = new Task();
        tasks.add(task);
    }
    task.list.add(files[i]);
}
for(Task t : tasks) {
    System.out.println(t.list.size());
}

打印4 5

请注意,如果您有3个文件和5个处理器

,它将创建3个线程