Episode ini membahas concurrency di Java: thread dasar, Runnable, dan thread lifecycle, ExecutorService, thread pool, dan task scheduling, synchronization, locks, atomic variable, dan concurrent collections, serta Java Flow API, reactive streams, dan struktur java.util.concurrent.

CPU modern memiliki banyak core, dan aplikasi yang memakai satu thread menyia-nyiakan kemampuannya. Episode 15 membahas concurrency dan parallelism di Java — cara menjalankan banyak tugas secara bersamaan dengan aman dan efisien.
Kalian akan belajar thread dasar dan lifecycle-nya, ExecutorService dan thread pool, sinkronisasi, atomic variable, concurrent collections, serta reactive streams.
Cara paling sederhana membuat thread adalah dengan Runnable:
public class ThreadDasar {
public static void main(String[] args) {
Runnable tugas = () -> System.out.println("Jalan di thread: "
+ Thread.currentThread().getName());
Thread t = new Thread(tugas);
t.start();
System.out.println("Thread utama selesai");
}
}new Thread(tugas).start() memulai thread secara asynchronous. Thread memiliki lifecycle: NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, dan TERMINATED — memahaminya membantu debugging concurrency.
Membuat thread baru untuk setiap tugas sangat mahal. ExecutorService mengelola kumpulan thread yang dipakai ulang — inilah thread pool:
import java.util.concurrent.*;
public class PoolExecutor {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(4);
for (int i = 0; i < 10; i++) {
final int nomor = i;
executor.submit(() ->
System.out.println("Tugas " + nomor + " di thread "
+ Thread.currentThread().getName()));
}
executor.shutdown();
}
}Executors.newFixedThreadPool(4) membuat pool dengan 4 thread yang dipakai bergantian untuk 10 tugas.
Untuk tugas terjadwal, gunakan ScheduledExecutorService:
import java.util.concurrent.*;
public class Jadwal {
public static void main(String[] args) {
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(() ->
System.out.println("Heartbeat"), 0, 2, TimeUnit.SECONDS);
}
}scheduleAtFixedRate menjalankan tugas setiap 2 detik — berguna untuk job periodik.
Tanpa sinkronisasi, banyak thread yang mengubah data bersama bisa memicu race condition. Keyword synchronized mengunci akses:
public class Counter {
private int nilai = 0;
public synchronized void increment() {
nilai++;
}
public int getNilai() {
return nilai;
}
}public synchronized void increment() memastikan hanya satu thread yang menambah nilai pada satu waktu.
Untuk operasi sederhana, atomic variable lebih efisien daripada synchronized:
import java.util.concurrent.atomic.AtomicInteger;
public class Atomik {
public static void main(String[] args) {
AtomicInteger nilai = new AtomicInteger(0);
nilai.incrementAndGet();
System.out.println(nilai.get());
}
}incrementAndGet() menambah nilai secara atomic tanpa kunci. Untuk data bersama, package java.util.concurrent menyediakan koleksi thread-safe:
import java.util.concurrent.ConcurrentHashMap;
public class KoleksiAman {
public static void main(String[] args) {
ConcurrentHashMap<String, Integer> stok = new ConcurrentHashMap<>();
stok.put("Laptop", 10);
stok.merge("Laptop", 1, Integer::sum);
System.out.println(stok.get("Laptop"));
}
}ConcurrentHashMap.merge aman dipanggil dari banyak thread sekaligus.
Reactive streams menangani pemrosesan data asinkron dengan backpressure — konsumen mengontrol kecepatan produksi data. Java 9 memperkenalkan Flow API dengan interface Publisher, Subscriber, Subscription, dan Processor:
import java.util.concurrent.Flow.*;
public class DemoFlow {
public static void main(String[] args) {
SubmissionPublisher<String> publisher = new SubmissionPublisher<>();
Subscriber<String> subscriber = new Subscriber<>() {
private Subscription subscription;
@Override
public void onSubscribe(Subscription subscription) {
this.subscription = subscription;
subscription.request(1);
}
@Override
public void onNext(String item) {
System.out.println("Menerima: " + item);
subscription.request(1);
}
@Override
public void onError(Throwable throwable) {
throwable.printStackTrace();
}
@Override
public void onComplete() {
System.out.println("Selesai");
}
};
publisher.subscribe(subscriber);
publisher.submit("data pertama");
publisher.close();
}
}Episode 15 membahas concurrency: thread dasar dan lifecycle, ExecutorService dengan thread pool dan scheduling, synchronization dan locks, atomic variable, concurrent collections, serta Java Flow API dan reactive streams.
Inti yang harus dibawa pulang:
new Thread(...).start() untuk thread sederhana; thread pool untuk skala.synchronized mencegah race condition pada data bersama.Di episode 16 selanjutnya kita akan membahas performance tuning dan garbage collection — profiling JVM dengan JVisualVM, JFR, dan Flight Recorder, memahami garbage collector G1, ZGC, dan Shenandoah, heap tuning dan JVM flags, pengukuran latency versus throughput, serta teknik optimalisasi kode. Saatnya membuat aplikasi yang cepat!