向单线程目录中所有文件迭代器实用函数添加多线程可能性
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 太值得了。
最直接的方式:
- (最棘手的部分)确保代码是线程安全的。不幸的是,很难给出更具体的建议 w/o 看到有问题的实际代码;
- 将代码包装到
Runnable\Callable
(匿名 class 或显式 class 其中 implements Runnable\Callable
;
这样您就可以在主线程(单线程版本)中调用您的 Runnable
或将其传递给 Executor
(多线程版本)。
一种方法是@Victor Sorokin 在他的回答中建议:将每个文件的处理包装在 Runnable
中,然后提交给 Executor
或仅调用 run()
主线程。
另一种可能性是 always 在 Runnable
中做同样的包装并提交给 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
我有一个连续(单线程)遍历文件目录的函数,将所有制表符缩进更改为三个 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 太值得了。
最直接的方式:
- (最棘手的部分)确保代码是线程安全的。不幸的是,很难给出更具体的建议 w/o 看到有问题的实际代码;
- 将代码包装到
Runnable\Callable
(匿名 class 或显式 class 其中implements Runnable\Callable
;
这样您就可以在主线程(单线程版本)中调用您的 Runnable
或将其传递给 Executor
(多线程版本)。
一种方法是@Victor Sorokin 在他的回答中建议:将每个文件的处理包装在 Runnable
中,然后提交给 Executor
或仅调用 run()
主线程。
另一种可能性是 always 在 Runnable
中做同样的包装并提交给 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