import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

public class ExecutorServiceDasar {
    public static void main(String[] args) throws Exception {
        ExecutorService eksekutor = Executors.newFixedThreadPool(2);
        try {
            // Task 1: Callable<String> -- lambda mengembalikan nilai.
            Future<String> tugasTeks = eksekutor.submit(
                    () -> "laporan penjualan siap");

            // Task 2: Callable<Integer> -- penjumlahan 1..100 di thread pool.
            Future<Integer> tugasHitung = eksekutor.submit(new Callable<Integer>() {
                @Override
                public Integer call() {
                    int total = 0;
                    for (int i = 1; i <= 100; i++) {
                        total += i;
                    }
                    return total;
                }
            });

            // Task 3: Runnable -- aksi tanpa nilai balik; tanda selesai
            // dikumpulkan lewat AtomicBoolean, bukan println dari dalam task.
            AtomicBoolean arsipBerjalan = new AtomicBoolean(false);
            Future<?> tugasAksi = eksekutor.submit(() -> {
                arsipBerjalan.set(true); // lakukan pengarsipan...
            });

            // get() menunggu masing-masing task selesai, lalu hasil dicetak
            // oleh main dalam urutan pemasukan -- deterministik.
            System.out.println("hasil tugas teks   : " + tugasTeks.get());
            System.out.println("hasil tugas hitung : " + tugasHitung.get());
            tugasAksi.get(); // tunggu Runnable selesai (mengembalikan null)
            System.out.println("tugas aksi selesai : " + arsipBerjalan.get());
            System.out.println("eksekutor masih hidup: " + !eksekutor.isTerminated());
        } finally {
            // Matikan eksekutor secara sopan: tolak task baru, tunggu task jalan.
            eksekutor.shutdown();
            if (!eksekutor.awaitTermination(5, TimeUnit.SECONDS)) {
                eksekutor.shutdownNow(); // belum selesai setelah 5 detik: paksa
            }
        }

        // Setelah shutdown, task baru pasti ditolak.
        try {
            eksekutor.submit(() -> System.out.println("tidak pernah berjalan"));
        } catch (RejectedExecutionException e) {
            System.out.println("task baru ditolak setelah shutdown");
        }
        System.out.println("eksekutor dimatikan: " + eksekutor.isTerminated());
    }
}
