0Pricing
Java Academy · Pelajaran

Stream Paralel: Kinerja dan Jebakan

Aktifkan stream paralel, pahami kumpulan thread umum, dan hindari bug akibat status mutable yang dibagikan.

Stream Paralel: Kinerja dan Jebakan adalah pelajaran Java Academy gratis di CoddyKit. Ini adalah pelajaran 2 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Java Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Java Academy mencakup 4 pelajaran total.

Mengaktifkan Aliran Paralel

Panggil .parallel() pada aliran apa pun, atau gunakan Collection.parallelStream(). Operasi aliran dijalankan pada ForkJoinPool bersama (bawaan: jumlah inti CPU - 1 utas).

long count = list.parallelStream()
    .filter(n -> n % 2 == 0)
    .count();
System.out.println(count);

Kapan Pemrosesan Paralel Menguntungkan

Aliran paralel layak digunakan ketika: kumpulan datanya besar (100.000+ elemen), operasi pada setiap elemen membutuhkan banyak komputasi, dan alurnya tidak memiliki keadaan serta tidak bergantung pada urutan.

// Good candidate: CPU-heavy computation on large dataset
long sum = LongStream.rangeClosed(1, 10_000_000)
    .parallel()
    .filter(n -> isPrime(n))
    .sum();
System.out.println(sum);

Kapan TIDAK Menggunakan Aliran Paralel

Hindari aliran paralel untuk: koleksi kecil, operasi yang terikat I/O (karena memblokir utas ForkJoinPool), operasi yang memiliki keadaan (seperti sorted dan distinct), atau ketika urutan penting dan mahal untuk dipulihkan.

// Bad: I/O bound — blocking ForkJoinPool threads starves other tasks
List<String> result = urls.parallelStream()
    .map(url -> httpGet(url)) // BLOCKS the common pool
    .collect(Collectors.toList());

Bug Keadaan Mutable Bersama

Aliran paralel menjalankan operasi pada beberapa utas secara bersamaan. Memodifikasi koleksi bersama yang dapat diubah menyebabkan perlombaan data dan hasil yang salah.

// RACE CONDITION — never do this:
List<Integer> results = new ArrayList<>(); // not thread-safe
numbers.parallelStream().forEach(n -> results.add(n)); // corrupts list!
// Fix:
List<Integer> safe = numbers.parallelStream().collect(Collectors.toList());

Operasi yang Memiliki Keadaan: sorted dan distinct

sorted() dan distinct() harus melihat semua elemen sebelum menghasilkan keluaran, sehingga membatasi paralelisme dan sering kali membuat pemrosesan paralel lebih lambat daripada pemrosesan berurutan.

// sorted() forces collect-all, then sort — parallel overhead usually not worth it:
list.parallelStream().sorted().collect(Collectors.toList());

Operasi yang Bergantung pada Urutan

findFirst() dan forEachOrdered() mempertahankan urutan kemunculan dalam aliran paralel, sehingga menambah biaya sinkronisasi. Gunakan findAny() atau forEach() jika urutan tidak penting.

// Faster in parallel (order-insensitive):
Optional<Integer> any = list.parallelStream().filter(n -> n > 10).findAny();
// Slower in parallel (must preserve order):
Optional<Integer> first = list.parallelStream().filter(n -> n > 10).findFirst();

Memilih Ukuran Kumpulan Utas

ForkJoinPool bersama menggunakan Runtime.getRuntime().availableProcessors() - 1 utas. Jalankan aliran paralel pada kumpulan khusus dengan mengirimkannya di dalam pemanggilan ForkJoinPool.invoke().

ForkJoinPool custom = new ForkJoinPool(8);
long result = custom.submit(
    () -> LongStream.rangeClosed(1, 1_000_000).parallel().sum()
).get();

Membandingkan Kinerja Paralel dan Berurutan

Selalu lakukan tolok ukur dengan JMH menggunakan ukuran data yang realistis. Biaya tambahan pemrosesan paralel (pemisahan, koordinasi utas, dan penggabungan) hanya sepadan jika waktu komputasi jauh lebih besar daripada biaya tambahan tersebut.

@Benchmark
public long sequential() { return LongStream.rangeClosed(1,1_000_000).sum(); }
@Benchmark
public long parallel()   { return LongStream.rangeClosed(1,1_000_000).parallel().sum(); }

Operasi Reduksi secara Paralel

reduce() dan collect() dirancang untuk bekerja dengan benar secara paralel ketika operasinya asosiatif dan nilai identitasnya benar.

// Associative reduce — safe in parallel:
int sum = list.parallelStream().reduce(0, Integer::sum);
// Non-associative: subtraction — NOT safe in parallel:
int bad = list.parallelStream().reduce(0, (a, b) -> a - b); // wrong result!

Kemampuan Membagi Itu Penting

Aliran paralel membagi sumber data menggunakan Spliterator. ArrayList dan array dapat dibagi dalam O(1); LinkedList dan HashSet sulit dibagi, sehingga mengurangi efisiensi paralel.

Ringkasan: Daftar Periksa Aliran Paralel

Sebelum menggunakan pemrosesan paralel: (1) kumpulan data besar, (2) operasi yang terikat CPU, (3) tidak ada keadaan mutable bersama, (4) tidak bergantung pada urutan, (5) sumber yang dapat dibagi (array/ArrayList). Jika ragu, lakukan tolok ukur.

Pemeriksaan Singkat

Apa yang terjadi ketika Anda menambahkan elemen ke koleksi yang tidak aman untuk utas dalam forEach pada aliran paralel?

Ringkasan

Aliran paralel menggunakan ForkJoinPool. Aliran ini efektif untuk alur pemrosesan yang besar, terikat CPU, tidak bergantung pada urutan, dan tidak memiliki keadaan. Jangan pernah memutasi keadaan bersama. Lakukan tolok ukur sebelum menetapkannya — pemrosesan paralel sering kali lebih lambat untuk data kecil.

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Stream Paralel: Kinerja dan Jebakan” gratis?

Ya — teks lengkap “Stream Paralel: Kinerja dan Jebakan” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Java Academy, upgrade ke CoddyKit PRO. Kursus Java Academy mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “Stream Paralel: Kinerja dan Jebakan”?

Aktifkan stream paralel, pahami kumpulan thread umum, dan hindari bug akibat status mutable yang dibagikan. Kamu berlatih Java Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai Java Academy?

Tidak diperlukan pengalaman sebelumnya. Java Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 2 dari 4.

Berapa lama pelajaran “Stream Paralel: Kinerja dan Jebakan” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran Java Academy ini?

Ya. Setiap pelajaran Java Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. flatMap untuk Koleksi Bersarang
  2. Stream Paralel: Kinerja dan Jebakan
  3. Spliterator: Pemisahan untuk Paralelisme
  4. Stream Tak Terbatas dengan iterate dan generate
← Kembali ke Java Academy