Создал программку которая считает кол-во файлов в указанных папках и выводит результат. Если не задействовать моногпоточность то выводит всё норм, как только пробую многопот то выводит одни 0.
public class CountFiles extends File implements Runnable {
private static FileFilter forFolder;
private static FileFilter forFile;
private static int countFilesToPrint;
private static List<String> list;
private static String pathname;
public static CountFiles countFiles;
public CountFiles(String pathname) {
super(pathname);
}
protected static void execute() {
countFilesToPrint = 0;
countFiles = new CountFiles(pathname);
if (!countFiles.isDirectory()) {
System.out.println(countFiles + " it's not a directory!");
return;
}
if (!countFiles.exists()){
System.out.println(countFiles + " is not exists!");
return;
}
forFolder = new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.isDirectory();
}
};
forFile = new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.isFile();
}
};
executeFolder(countFiles);
}
protected static void executeFolder(File nameFolder){
File[] file = nameFolder.listFiles(forFile);
File[] folder = nameFolder.listFiles(forFolder);
countFilesToPrint = countFilesToPrint + file.length;
for (File file2 : folder){
executeFolder(file2);
}
}
@Override
public void run() {
execute();
}
public static void main(String[] args) {
list = Arrays.asList("D:\\Java", "D:\\Load_Tools", "D:\\data");
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < list.size(); i++){
pathname = list.get(i);
executorService.execute(new CountFiles(pathname));
System.out.println(list.get(i) + " - " + countFilesToPrint);
}
executorService.shutdown();
}
}
Снова таки, я не джава программист, но вы запускаете отдельный поток, в котором читаете файлы а в основном процессе тут же выводите список файлов, до того как дочерний процесс отработал. Если запустить на пентиум 1 с 400 мгц частоты, может и сработает =)
Вобщем, скорее всего причина в этом.
Вы правильно сказали, по-этому нужно создать какую-то темповую очередь из фолдеров и по ней ходить потоками, что бы потоки не ходили и не обнуляли уже пройденный фолдер другим потоком.
Ага, иcпользуйте AtomicInteger если нужно общее количество файлов и инкрементируйте его из каждого потока. В данном случае объявлять его как volatile, вроде, не требуется. Просто static.
Тут же можете поиграться с parallel() / parallelStream() и замерить performance. Хотя, очень сомневаюсь, что выиграете в производительности на маленьких выборках. Даже наоборот, скорее потеряете.
Если же надо просто посчитать общее число файлов:
long items = Arrays.asList("path1", "path2", "pathN")
.stream()
.distinct()
.mapToLong(HostClass::walkThrough)
.sum();
П.С. В случае со стримами, вам вряд ли удастся ошибиться с shared объектами.
Вот тут то и срабатывает принципиально ограничение стримов, которые не надут вам использовать не final / effectively final объекты из-вне в лямбдах. Это сделано как раз с той точки зрения, чтобы потоки не имели возможности изменять состояние mutable объектов, что привело бы к непредсказуемым последствиям при параллельном экзекьюшене. Конечно технически вы все-таки сможете изменять shared state какому-нибудь аккумулятору внутри объекта. Но это будут проблемы самого алгоритма, а не неверной работы потоков, в случае fail результатов. В Java 8 весь effort по многопоточности стримов реализован internally через fork/join framework. Но сами создатели предупреждают, что не следует бездумно включать опцию parallelStream(), т.к. при определенных условиях затраты на подготовку могут быть выше, нежели при последовательном запуске. Потому, в случае параллелизации желательно всегда делать замеры через JMH, проводить предварительную оптимизацию (по типу boxing / unboxing операций), избегать операций, зависящих от порядка (limit / findFirst), ordered коллекций, маленьких выборок т.п.