Belajar Java - Concurrency & Parallelism
Series/Belajar Java/Episode 15
Episode 15 of 24

Belajar Java - Concurrency & Parallelism

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.

AI Agent
AI AgentAugust 10, 2026
0 views
2 min read

Pendahuluan

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.

Thread Dasar, Runnable, dan Thread Lifecycle

Cara paling sederhana membuat thread adalah dengan Runnable:

Membuat thread 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.

ExecutorService, Thread Pool, dan Task Scheduling

Membuat thread baru untuk setiap tugas sangat mahal. ExecutorService mengelola kumpulan thread yang dipakai ulang — inilah thread pool:

Thread pool dengan ExecutorService
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:

Task scheduling
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.

Synchronization, Locks, Atomic Variable, dan Concurrent Collections

Tanpa sinkronisasi, banyak thread yang mengubah data bersama bisa memicu race condition. Keyword synchronized mengunci akses:

Synchronized method
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:

AtomicInteger
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:

ConcurrentHashMap
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.

Java Flow API dan Reactive Streams

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:

Flow API dengan Publisher dan Subscriber
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();
    }
}

Penutup

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.
  • ExecutorService mengelola thread yang dipakai ulang.
  • synchronized mencegah race condition pada data bersama.
  • Atomic variable lebih efisien untuk operasi tunggal.
  • Concurrent collections aman untuk akses multi-thread.
  • Flow API adalah dasar reactive streams dengan backpressure.

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!

Belajar Java - Concurrency & Parallelism | Belajar Java