Многопоточность Java с открытием файлов - PullRequest
0 голосов
/ 01 ноября 2018

У меня есть текстовый файл: order_me.txt, в котором есть несколько целых чисел, которые нужно отсортировать, используя 4 потока. Им нужно работать одновременно, но не делать одно и то же. Мне удалось отсортировать целые числа, но что-то не работает правильно ...

Это нить класса:

public class Threading {

    static List<Integer> integersCopy = new ArrayList<>();

    public static void main(String[] args) {
        openFile();
        Thread t1 = new Thread(new Command("thread 1", integersCopy));
        t1.start();

        Thread t2 = new Thread(new Command("thread 2", integersCopy));
        t2.start();

        Thread t3 = new Thread(new Command("thread 3", integersCopy));
        t3.start();

        Thread t4 = new Thread(new Command("thread 4", integersCopy));
        t4.start();

        try {
            if (t1.isAlive())
                t1.join();
            if (t2.isAlive())
                t2.join();
            if (t3.isAlive())
                t3.join();
            if (t4.isAlive())
                t4.join();
        } catch (Exception e) {
            System.out.println("Exception with threads");
        }
    }

    public static void openFile() {
        File file = new File("order_me.txt");
        try {
            Scanner scanner = new Scanner(file);
            List<Integer> integers = new ArrayList<>();
            while (scanner.hasNext()) {
                if (scanner.hasNextInt()) {
                    integers.add(scanner.nextInt());
                } else {
                    scanner.next();
                }
            }
            integersCopy = integers;
            System.out.println("File opened successfully");

        } catch (Exception e) {
            System.out.println("Triggered exception");
        }
    }

А это класс сортировки:

    import java.util.Collections;
    import java.util.List;

    public class Command implements Runnable {
    String threadName;
    List<Integer> listOfInts;

    Command(String name, List<Integer> list) {
        threadName = name;
        listOfInts = list;
    }

    @Override
    public void run() {
        for (int i = 0; i < listOfInts.size(); i++) {
            Collections.sort(listOfInts);
            System.out.print(+listOfInts.get(i) + " ");
        }
    }
}

Ответы [ 2 ]

0 голосов
/ 01 ноября 2018

Вы изменяете общий List в нескольких потоках. ArrayList не потокобезопасен : вам нужно либо использовать потокобезопасный Collection, либо использовать Collections.synchronizedList.

И если вы сортируете один и тот же список в каждом потоке, то вы, вероятно, ошибаетесь в своей реализации:

  • Вы должны прочитать список один раз в родительской ветке
  • Вы должны разделить список по номеру потока и отсортировать каждый подсписок в каждом собственном потоке. Это цель Thread в таком случае: разделить работу на выполнение.
  • Затем вы должны присоединиться к подсписку в родительском потоке: во время процесса объединения вам придется сортировать. Поскольку каждый подсписок отсортирован, вы можете использовать более быструю сортировку (например: если первый элемент подсписка A, если после последнего подсписка B, то вы можете добавить все элементы A в B) или стандартная сортировка.

Кроме того, вы можете использовать Stream для этого:

  • Метод parallel() заставляет Stream использовать несколько потоков.
  • ForkJoinPool используется для использования другого пула потоков (см. этот ответ SO ). Это может быть бесполезно для примера.
  • К сожалению, Scanner не переводится в IntStream или Stream. Вам нужно использовать Files.lines и Pattern для разделения строки по пробелам (\s+).
  • Мы используем flatMapToInt для преобразования в IntStream OptionalInt (для пустого номера он будет пустым, например: *a4).
  • sorted() убедитесь, что мы сортируем, используя сортировку по умолчанию. Сортировка с использованием компаратора потребует обычного потока и, следовательно, flatMapToInt будет изменено на flatMap.
  • toArray(), вероятно, лучше в этом случае, чем использовать ArrayList из Integer, как во втором примере.

Код, протестированный с Java 11:

  public static void main(final String[] args) throws Exception {
    final Pattern splitter = Pattern.compile("\\s+");
    // see
    // 
    final ForkJoinPool forkJoinPool = new ForkJoinPool();
    final Future<int[]> future = forkJoinPool.submit(() -> {
      try (final Stream<String> lines = Files.lines(Paths.get("myfile.txt"), StandardCharsets.UTF_8)) {
        return lines.parallel() // use default parallel ExecutorService
            .flatMap(splitter::splitAsStream) // tokenize input
            .flatMapToInt(s -> parseInt(s).stream()) // convert to number (eg: nextInt())
            .sorted().toArray();
      }
    });

    final int[] result = future.get();
    System.out.println("result.length: " + result.length);
    // Arrays.stream(result).forEach(System.out::println);
    final Future<List<Integer>> future2 = forkJoinPool.submit(() -> {
      try (Stream<String> lines = Files.lines(Paths.get("myfile.txt"), StandardCharsets.UTF_8)) {
        return lines.parallel() // use default parallel ExecutorService
            .flatMap(splitter::splitAsStream) // tokenize input
            .flatMapToInt(s -> parseInt(s).stream()) // convert to number (eg: nextInt())
            .sorted().collect(ArrayList::new, List::add, List::addAll) // probably best to use
                                                                       // array.
        ;
      }
    });
    final List<Integer> result2 = future2.get();
    System.out.println("result2.length: " + result2.size());
  }

  static OptionalInt parseInt(final String s) {
    try {
      return OptionalInt.of(Integer.parseInt(s));
    } catch (final NumberFormatException e) {
      return OptionalInt.empty();
    }
  }
0 голосов
/ 01 ноября 2018

После того, как один поток отсортировал целые числа, нет смысла пытаться делать одно и то же в нескольких потоках, так как это не сделано потокобезопасным способом, вы, скорее всего, испортите список.

Короче говоря, используйте одну нить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...