向单线程目录中所有文件迭代器实用函数添加多线程可能性

Adding multi-threading possibility to a single-threaded all-files-in-directory iterator utility function

我有一个连续(单线程)遍历文件目录的函数,将所有制表符缩进更改为三个 space 缩进。

我将它用作我对多线程的第一次尝试。 ( Java Concurrency in Practice...很惊讶它现在已经八岁了。)

为了保持当前的单线程功能,但增加多线程的额外可能性,我正在考虑更改函数以接受额外的 Executor parameter, where the original single-threaded function would now be a call to it, passing in a single threaded executor

这样做合适吗?

如果您使用的是 Java 8,我发现 parallelStream 是实现多线程的最简单方法

    List<File> files = Arrays.asList(getDirectoryContents());
    files.parallelStream().forEach( file -> processFile(file));

如果你想在单线程和多线程之间切换,你可以简单地传递一个布尔标志

    List<File> files = Arrays.asList(getDirectoryContents());
    if(multithreaded){
      files.parallelStream().forEach( file -> processFile(file));
    }else{
      files.stream().forEach(file -> processFile(file));
    }

我希望我能为 Java 7 提供帮助,但我一夜之间从 Java 5 变成了 8。 :) Java 8 太值得了。

最直接的方式:

  1. (最棘手的部分)确保代码是线程安全的。不幸的是,很难给出更具体的建议 w/o 看到有问题的实际代码;
  2. 将代码包装到 Runnable\Callable(匿名 class 或显式 class 其中 implements Runnable\Callable;

这样您就可以在主线程(单线程版本)中调用您的 Runnable 或将其传递给 Executor(多线程版本)。

一种方法是@Victor Sorokin 在他的回答中建议:将每个文件的处理包装在 Runnable 中,然后提交给 Executor 或仅调用 run()主线程。

另一种可能性是 alwaysRunnable 中做同样的包装并提交给 always-given Executor.

是否同时执行每个文件的处理将取决于给定的 Executor 的实现。

对于并行处理,您可以调用您的函数传递它,即 ThreadPoolExecutor 作为参数,而对于顺序处理,您可以传递一个假的 Executor,即运行提交任务的函数调用者线程:

public class FakeExecutor implements Executor {

    @Override
    public void execute(Runnable task) {
        task.run();
    }
}

我认为这种方式是最灵活的方式。

创建 class 的方法之一是实现 Executor 接口,它将在主线程中执行您的代码。像这样:

public class FileProcessor implements Runnable {

    private final File file;

    public FileProcessor(File file) {
        this.file = file;
    }

    @Override
    public void run() {
        // do something with file
    }
}

public class DirectoryManager {

    private final Executor executor;

    public DirectoryManager() {
        executor = new Executor() {
            @Override
            public void execute(Runnable command) {
                command.run();
            }
        };
    }

    public DirectoryManager(int numberOfThreads) {
        executor = Executors.newFixedThreadPool(numberOfThreads);
    }

    public void process(List<File> files) {
        for (File file : files) {
            executor.execute(new FileProcessor(file));
        }
    }
}

并在您的代码中这样调用它

DirectoryManager directoryManager = new DirectoryManager();
directoryManager.process(lists);
// some other sync code

或者这个

DirectoryManager directoryManager = new DirectoryManager(5);
directoryManager.process(lists);
// some other async code