Springboot— Thread
hari ke 25 mencoba konsisten menulis, kali ini kita mencoba untuk membahas tentang thread
Apa itu Thread?
Thread adalah unit eksekusi terkecil dalam sebuah proses. Di Spring Boot, thread management sangat penting karena menentukan bagaimana aplikasi menangani request secara bersamaan.
🔄 Default Thread Model Spring Boot
Spring Boot menggunakan Tomcat sebagai embedded server secara default, yang bekerja dengan model thread-per-request:
Request masuk → Tomcat ambil thread dari pool
→ Proses request → Thread dikembalikan ke poolJenis Thread di Spring Boot
1. Request Thread (Tomcat Thread Pool)
Menangani HTTP request masuk. Konfigurasi di application.properties:
server.tomcat.threads.min-spare=10
server.tomcat.threads.max=200
server.tomcat.accept-count=1002. @Async Thread (Task Executor)
Untuk menjalankan method secara asynchronous di background:
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean(name = "taskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("AsyncThread-");
executor.initialize();
return executor;
}
}@Service
public class EmailService {
@Async("taskExecutor")
public CompletableFuture<Void> sendEmail(String to) {
// Jalan di thread terpisah, tidak blocking request utama
System.out.println("Running in: " + Thread.currentThread().getName());
// ... logic kirim email
return CompletableFuture.completedFuture(null);
}
}Apa itu ThreadPoolTaskExecutor?
Get Arif Dwi Prasetya’s stories in your inbox
Join Medium for free to get updates from this writer.
ThreadPoolTaskExecutor adalah implementasi Spring untuk mengelola pool of threads — kumpulan thread yang siap pakai, sehingga tidak perlu membuat thread baru setiap kali ada task.
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5); // Jumlah thread tetap yang selalu hidup
executor.setMaxPoolSize(20); // Maksimum thread yang bisa dibuat
executor.setQueueCapacity(100); // Kapasitas antrian task
executor.setKeepAliveSeconds(60); // Berapa lama extra thread hidup jika idle
executor.setThreadNamePrefix("MyThread-");
executor.initialize();Visualisasi Alur Kerja
Task ke-1 sampai ke-5 masuk
└──► Langsung diproses CorePoolSize (5 thread aktif)
Task ke-6 sampai ke-105 masuk (saat core threads sibuk)
└──► Masuk ke Queue (kapasitas 100)
Task ke-106 masuk (queue sudah penuh)
└──► Buat thread baru hingga MaxPoolSize (20)
Task ke-121 masuk (queue penuh + max thread tercapai)
└──► RejectedExecutionHandler dipanggil! ❌3. Scheduled Thread
Untuk task yang berjalan berkala:
@Configuration
@EnableScheduling
public class SchedulerConfig {
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(5);
scheduler.setThreadNamePrefix("Scheduler-");
return scheduler;
}
}@Component
public class ReportJob {
@Scheduled(cron = "0 0 8 * * *") // Setiap hari jam 8 pagi
public void generateDailyReport() {
System.out.println("Running in: " + Thread.currentThread().getName());
// ... logic generate report
}
}⚠️ Masalah Umum Thread
1. Thread Blocking
// ❌ BURUK — blocking thread saat I/O
@GetMapping("/data")
public String getData() {
Thread.sleep(5000); // Block thread 5 detik!
return "done";
}
// ✅ BAIK — gunakan async
@GetMapping("/data")
public CompletableFuture<String> getData() {
return CompletableFuture.supplyAsync(() -> {
// ... proses berat
return "done";
});
}Apa itu CompletableFuture?
CompletableFuture adalah class di Java 8+ untuk menjalankan task secara asynchronous dan non-blocking, serta bisa di-chain, dikombinasikan, dan ditangani error-nya secara elegan.
2. Thread Safety — Race Condition
// ❌ BURUK — shared mutable state
@Service
public class CounterService {
private int count = 0; // Tidak thread-safe!
public void increment() {
count++; // Bisa corrupt jika diakses bersamaan
}
}
// ✅ BAIK — gunakan AtomicInteger
@Service
public class CounterService {
private AtomicInteger count = new AtomicInteger(0);
public void increment() {
count.incrementAndGet(); // Thread-safe
}
}3. ThreadLocal — Data per Thread
// Menyimpan data yang spesifik per thread (misal: user context)
public class UserContext {
private static final ThreadLocal<String> currentUser = new ThreadLocal<>();
public static void set(String user) { currentUser.set(user); }
public static String get() { return currentUser.get(); }
// WAJIB clear setelah selesai, hindari memory leak!
public static void clear() { currentUser.remove(); }
}4. Virtual Thread (Java 21 + Spring Boot 3.2+)
# application.properties — aktifkan virtual thread
spring.threads.virtual.enabled=trueRingkasan Kapan Pakai Apa
Sekian thread singkat semoga bermanfaat, terima kasih.
— Arif Dwi Prasetya










