Вы изменяете общий 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();
}
}