Spliterator: разделение для параллельной обработки
Реализуйте собственный Spliterator, чтобы предоставить данные предметной области как источник потока, поддерживающий разделение.
«Spliterator: разделение для параллельной обработки» — бесплатный урок Java Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Java Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Java Academy содержит 4 уроков всего.
Что такое Spliterator
Spliterator (разделяемый итератор) — это основной механизм потоков. Он обходит элементы и может разделить себя на две части для параллельной обработки.
Основные методы Spliterator
Четыре основных метода: tryAdvance (обработка одного элемента), forEachRemaining (обработка всех оставшихся элементов), trySplit (разделение на две части), estimateSize (оценка количества элементов).
Spliterator<Integer> sp = List.of(1,2,3,4,5,6).spliterator();
Spliterator<Integer> half = sp.trySplit(); // splits off first ~half
half.forEachRemaining(System.out::println); // 1 2 3
sp.forEachRemaining(System.out::println); // 4 5 6Характеристики Spliterator
Spliterator объявляют свои характеристики с помощью битовых флагов: SIZED, ORDERED, DISTINCT, SORTED, NONNULL, IMMUTABLE, CONCURRENT, SUBSIZED.
Spliterator<String> sp = List.of("a","b","c").spliterator();
System.out.println(Integer.toBinaryString(sp.characteristics()));
// Characteristics include ORDERED, SIZED, SUBSIZEDКак работает trySplit
trySplit() возвращает новый Spliterator, охватывающий примерно половину оставшихся элементов. Исходный охватывает другую половину. Возвращайте null, если разделение невозможно.
// ArrayList Spliterator splits efficiently at midpoint:
// [0,1,2,3,4,5] -> [0,1,2] (new) + [3,4,5] (original)Создание пользовательского Spliterator
Реализуйте Spliterator<T>, чтобы представить пользовательскую структуру данных как источник потока. Определите trySplit, чтобы обеспечить параллельную обработку.
public class RangeSpliterator implements Spliterator<Integer> {
private int start, end;
public RangeSpliterator(int start, int end) { this.start=start; this.end=end; }
public boolean tryAdvance(Consumer<? super Integer> action) {
if (start >= end) return false;
action.accept(start++); return true;
}
public Spliterator<Integer> trySplit() {
int mid = (start + end) / 2;
if (mid <= start) return null;
RangeSpliterator prefix = new RangeSpliterator(start, mid);
this.start = mid; return prefix;
}
public long estimateSize() { return end - start; }
public int characteristics() { return ORDERED | SIZED | SUBSIZED | IMMUTABLE; }
}Создание потока из Spliterator
Используйте StreamSupport.stream(spliterator, parallel), чтобы создать поток из любого Spliterator — связующее звено между пользовательскими источниками данных и API потоков.
Spliterator<Integer> sp = new RangeSpliterator(0, 1_000_000);
Stream<Integer> stream = StreamSupport.stream(sp, true); // true = parallel
long count = stream.filter(n -> n % 2 == 0).count();
System.out.println(count); // 500000Spliterator для бинарного дерева
Пользовательские Spliterator обеспечивают параллельную обработку структур, не являющихся списками, например деревьев. trySplit возвращает Spliterator левого поддерева, сохраняя правое.
Эффективность параллельной обработки и качество разделения
Параллельные потоки рекурсивно разделяются, пока части не станут достаточно маленькими для одного потока. Для качественного разделения необходимо, чтобы estimateSize давал точную оценку, а части были примерно равными.
forEachRemaining для пакетной обработки
Если разделение не требуется, переопределите forEachRemaining для пакетной обработки, позволяющей избежать накладных расходов на каждый элемент при вызове tryAdvance в цикле.
@Override
public void forEachRemaining(Consumer<? super Integer> action) {
for (int i = start; i < end; i++) action.accept(i);
start = end; // mark as exhausted
}Spliterator и Iterator
Iterator: только последовательный обход, без оценки размера и разделения. Spliterator: поддерживает параллельную обработку, предоставляет характеристики и оценку размера, предназначен для API потоков.
Быстрая проверка
Что возвращает trySplit(), если разделение невозможно?
Итоги
Spliterator — это механизм параллельных потоков. Реализуйте tryAdvance, trySplit, estimateSize и characteristics, чтобы предоставлять пользовательские структуры данных как потоки. Используйте StreamSupport.stream(sp, true) для перехода к параллельной обработке.
Часто задаваемые вопросы
Урок «Spliterator: разделение для параллельной обработки» бесплатный?
Да — полный текст урока «Spliterator: разделение для параллельной обработки» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Java Academy, подпишись на CoddyKit PRO. Курс Java Academy содержит 4 уроков всего.
Чему я научусь в уроке «Spliterator: разделение для параллельной обработки»?
Реализуйте собственный Spliterator, чтобы предоставить данные предметной области как источник потока, поддерживающий разделение. Ты практикуешь Java Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Java Academy?
Предыдущий опыт не требуется. Java Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Spliterator: разделение для параллельной обработки»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Java Academy?
Да. Каждый урок Java Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- flatMap для вложенных коллекций
- Параллельные потоки: производительность и подводные камни
- Spliterator: разделение для параллельной обработки
- Бесконечные потоки с iterate и generate