Добавление возможности многопоточности в однопоточную утилиту-итератор all-files-in-directory

1

У меня есть функция, которая последовательно (однопоточно-ly) выполняет итерацию через каталог файлов, изменяя все отступы от вкладок до трехмерного отступа.

Я использую его в качестве первой попытки многопоточности. (Я больше всего использую Java Concurrency на практике... удивил его восемь лет.)

Чтобы сохранить текущую однопоточную функциональность, но добавьте дополнительную возможность многопоточности, я думаю об изменении функции, чтобы принять дополнительный параметр Executor, где исходная однопоточная функция теперь будет вызовом он, проходящий в одном поточном исполнителе.

Это подходящий способ сделать это?

Теги:
multithreading
executor
java-7

4 ответа

1
Лучший ответ

Один из способов заключается в том, что @Victor Сорокин предлагает в своем ответе: обернуть обработку каждого файла в Runnable а затем либо отправить в Executor либо просто вызвать run() из основного потока.

Другая возможность состоит в том, чтобы всегда делать одно и то же обертывание в Runnable и передавать его всегда предоставленному Executor.

Независимо от того, выполняется ли обработка каждого файла одновременно или нет, будет зависеть от данной реализации Executor.

Для параллельной обработки вы можете ссылаться на свою функцию, передавая ее, т.е. ThreadPoolExecutor в качестве аргумента, тогда как для последовательной обработки вы можете передать поддельный Executor, то есть тот, который выполняет предоставленные задачи в потоке вызывающего:

public class FakeExecutor implements Executor {

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

Я считаю, что это самый гибкий подход.

  • 0
    Есть ли разница между немедленным выполнением задачи и выполнением ее через однопоточный пул потоков (однопоточный исполнитель)?
  • 0
    @aliteralmind Да! Выполнение задачи немедленно означает, что все выполняется последовательно. При выполнении с однопоточным исполнителем он запускается параллельно.
Показать ещё 4 комментария
2

Если вы используете 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 стоит sooooooo.

  • 0
    Я использую Java 7. Добавил тег. Будет иметь это в виду.
1

Один из способов создания класса реализует интерфейс 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
  • 1
    Я не видел предыдущих ответов, в общем я написал тоже самое что и @Magnamag
1

Самый простой способ:

  1. (Самая сложная часть) Убедитесь, что код является потокобезопасным. К сожалению, трудно дать более конкретные рекомендации без просмотра фактического кода;
  2. Заменить код в Runnable\Callable (либо анонимный класс, либо явный класс, который implements Runnable\Callable;

Таким образом, вы сможете либо вызвать свой Runnable в основном потоке (однопоточной версии), либо передать его в Executor (многопоточная версия).

Ещё вопросы

Сообщество Overcoder
Наверх
Меню