Назначение задач существующим потокам, как только они станут свободными java

#java #multithreading

#java #многопоточность

Вопрос:

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

В настоящее время я использую именно этот код:

     public static void main(String[] args) {
        System.setProperty("http.agent", "Chrome");
        readWords();
        Collections.shuffle(words);
        words.forEach(word -> {
            if (CheckValidity.checkValidity(word)) {
                System.out.println(word);
                try(PrintWriter writer = new PrintWriter(new FileWriter("output.txt",true)))
                {
                    writer.printf("%srn", word);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
        System.out.println("Done!");
    }
  

Как бы я реализовал это в многопоточности? Я не смог найти никакой информации, которая имела бы смысл для меня, где я мог бы ввести значение в метод любого свободного потока. Извините, если это не совсем так, как работает многопоточность, я никогда раньше ничего не писал с более чем одним потоком, поэтому я не знаю, что возможно, а что нет.

Комментарии:

1. В этом случае узким местом могут быть операции ввода-вывода (запись в выходной файл). Вы (вероятно) не получите многого от многопоточности здесь.

2. Тем не менее, похоже, что вы пытаетесь заново изобрести ThreadPoolExecutor . JavaDocs этого класса (и те, на которые ссылаются оттуда) являются хорошей отправной точкой.

3. Или, возможно, параллельные потоки являются более подходящей абстракцией для вас — см. Описание пакета java.util.stream .

4. хорошо, я проверю это. Узким местом определенно являются не операции ввода-вывода, а то, что отнимает больше всего времени, — это проверка слов с помощью API, поэтому время, необходимое для ответа веб-сайта, является узким местом.

5. В любом случае, почти наверняка быстрее сначала собрать допустимые слова в памяти и записывать в файл только после того, как вы закончите.

Ответ №1:

Самый быстрый способ распараллелить ваши вызовы CheckValidity — использовать параллельный поток. Что-то вроде

 public static void main(String[] args) {

        List<String> words = readWords();
        Collections.shuffle(words);

        words.stream()
            .unordered()
            .parallel()
            .filter(CheckValidity::checkValidity)
            .forEach(word -> {
                System.out.println(word);
                try(PrintWriter writer = new PrintWriter(new FileWriter("output.txt",true)))
                {
                    writer.printf("%srn", word);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                
            });
        System.out.println("Done!");
    }
  

Однако это не должно быть вашим производственным решением, если ваше приложение также выполняет другие действия параллельно, поскольку при этом внутренне используется общий ForkJoinPool, и блокирование этого с помощью операций, не связанных с процессором, может замедлить работу других частей вашего приложения (например, других параллельных потоков).

Для более надежного решения вам следует взглянуть на ThreadPoolExecutor, который позволяет создавать отдельные пулы потоков с определенными размерами, тайм-аутами и т.д.

Комментарии:

1. Спасибо, я смог использовать параллельный поток, который вы мне дали, и эту статью, чтобы ускорить работу моей программы примерно на 10 таймеров.