Kuasai pola singleton Java dengan panduan kami tentang keamanan-thread, pengujian, dan alternatif modern seperti injeksi dependensi untuk kode yang mudah dipelihara dan dapat diskalakan.
January 28, 2026 (2mo ago)
Panduan Pola Singleton Java untuk Kode Bersih
Kuasai pola singleton Java dengan panduan kami tentang keamanan-thread, pengujian, dan alternatif modern seperti injeksi dependensi untuk kode yang mudah dipelihara dan dapat diskalakan.
← Back to blog
Panduan Pola Singleton Java untuk Kode Bersih
Ringkasan: Kuasai pola singleton Java dengan panduan kami tentang keamanan-thread, pengujian, dan alternatif modern seperti injeksi dependensi untuk kode yang mudah dipelihara dan dapat diskalakan.
Pendahuluan
Pola Singleton di Java memastikan bahwa sebuah kelas hanya memiliki satu instans dan menyediakan satu titik akses global ke instans tersebut. Ini berguna untuk objek seperti pengelola konfigurasi, pool koneksi, atau layanan logging sentral di mana banyak instans akan menyebabkan status yang tidak konsisten atau pemborosan sumber daya. Memahami cara mengimplementasikan Singleton yang aman, dapat diuji — dan kapan harus menghindarinya — adalah penting untuk kode Java yang bersih dan mudah dipelihara.
Memahami Pola Desain Singleton

Analogi yang membantu adalah menara pengendalian lalu lintas udara di sebuah bandara. Anda tidak membangun menara terpisah untuk setiap pesawat; setiap pesawat berkomunikasi dengan menara yang sama. Menara adalah sumber kebenaran tunggal. Itulah peran yang dimainkan Singleton dalam sebuah aplikasi.
Pola ini dipopulerkan dalam literatur pola desain klasik dan dalam sistem Java enterprise1. Tanggung jawab inti pola ini sederhana:
- Menjamin satu instans — biasanya dengan membuat konstruktor menjadi private.
- Menyediakan titik akses global — biasanya metode statis seperti getInstance().
Karakteristik Utama
- Hanya satu instans: Kelas mencegah pembuatan lebih dari satu instans.
- Konstruktor private: Mencegah instansiasi langsung oleh kelas lain.
- Titik akses global: Metode statis mengembalikan instans tunggal.
- Siklus hidup yang dikendalikan sendiri: Kelas mengelola instansnya sendiri.
Intisari: Singleton menegakkan satu objek dan akses global yang terkontrol sehingga bagian-bagian berbeda dari sebuah aplikasi berbicara kepada instans yang persis sama.
Mengimplementasikan Singleton yang Aman terhadap Thread di Java

Singleton dengan inisialisasi lazy yang naif sederhana tetapi tidak aman terhadap thread. Pertimbangkan contoh dasar ini:
public class BasicLazySingleton {
private static BasicLazySingleton instance;
private BasicLazySingleton() {}
public static BasicLazySingleton getInstance() {
if (instance == null) {
instance = new BasicLazySingleton();
}
return instance;
}
}
Dalam lingkungan multi-thread, dua thread dapat melihat instance == null dan keduanya membuat instans baru. Perbaikan yang langsung adalah mensinkronkan getInstance(), tetapi itu menyebabkan penguncian yang tidak perlu pada setiap panggilan.
Metode Sinkronisasi (berfungsi, tetapi mahal)
public class SynchronizedSingleton {
private static SynchronizedSingleton instance;
private SynchronizedSingleton() {}
public static synchronized SynchronizedSingleton getInstance() {
if (instance == null) {
instance = new SynchronizedSingleton();
}
return instance;
}
}
Ini menyelesaikan masalah keamanan-thread tetapi mengurangi performa karena sinkronisasi dijalankan pada setiap akses.
Bill Pugh (Initialization-on-demand Holder)
Pendekatan yang lebih bersih adalah idiom Initialization-on-demand Holder. Ini memberikan inisialisasi lazy dan keamanan-thread tanpa overhead sinkronisasi karena inisialisasi kelas aman-thread di JVM2.
public class BillPughSingleton {
private BillPughSingleton() {}
private static class SingletonHolder {
private static final BillPughSingleton INSTANCE = new BillPughSingleton();
}
public static BillPughSingleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
Ini bergantung pada JVM untuk memuat SingletonHolder hanya ketika getInstance() dipanggil, dan jaminan inisialisasi kelas menyediakan keamanan-thread.
Enum Singletons (direkomendasikan)
Joshua Bloch merekomendasikan menggunakan enum ber-elemen tunggal untuk sebuah Singleton. Ini ringkas dan melindungi terhadap serangan refleksi dan serialisasi3.
public enum EnumSingleton {
INSTANCE;
public void someMethod() {
// business logic
}
}
Manfaat:
- Kode minimal
- Keamanan-thread disediakan oleh JVM
- Keamanan serialisasi
- Perlindungan kuat terhadap pembuatan instans berbasis refleksi
Untuk sebagian besar kasus, enum Singleton adalah pilihan yang paling tangguh dan mudah dipelihara.
Biaya Tersembunyi dari Pola Singleton

Meskipun Singletons memecahkan masalah tertentu, mereka memperkenalkan biaya tersembunyi: ketergantungan yang ketat, state global, dan berkurangnya kemampuan untuk diuji.
Saat kode memanggil Singleton.getInstance(), ketergantungan itu tersembunyi. Kontrak publik kelas tidak mengungkapkan bahwa ia bergantung pada objek global. Ini menyebabkan:
- Kode yang kaku dan sulit diubah
- Pengujian yang rapuh atau memerlukan instans global yang sebenarnya
- Kesulitan menjalankan pengujian secara paralel karena state yang dibagi
Masalah Pengujian
Singleton membuat pengujian unit terisolasi menjadi sulit. Anda tidak bisa dengan mudah menukar mock, jadi pengujian sering menggunakan implementasi nyata. Itu dapat menyebabkan pengujian lambat, keterikatan yang tidak disengaja ke sistem eksternal, dan pipeline CI yang rapuh.
Sebuah kelas yang bergantung pada Singleton menyembunyikan ketergantungan itu dari tanda tangannya, yang membuat kode lebih sulit untuk dipahami dan dipelihara.
State Global dan Ketergantungan Tersembunyi
Singleton pada dasarnya adalah variabel global. State global menyamarkan aliran informasi dan menciptakan saling ketergantungan yang sulit untuk diuraikan. Ini mempersulit debugging dan memperlambat pengembangan.
Untuk lebih lanjut tentang antipola umum dan keterpeliharaan, lihat panduan kami tentang pola desain dalam OOP dan strategi pengujian.
Alternatif Modern untuk Singleton
Seiring perkembangan sistem, pengembang mengadopsi pola yang menghindari kelemahan Singleton sambil mempertahankan pengendalian pembuatan objek.
Injeksi Dependensi
Injeksi dependensi membalik tanggung jawab: klien mendeklarasikan dependensinya, dan kontainer eksternal menyediakannya. Ini membuat dependensi eksplisit dan mudah diganti dalam pengujian. Framework DI seperti Spring dan Guice mengelola siklus hidup objek dan pengkabelan untuk Anda4.
Manfaat Injeksi Dependensi:
- Dekopling — komponen bergantung pada abstraksi, bukan kelas konkrit
- Kemampuan diuji — Anda bisa menyuntikkan mock atau fake
- Fleksibilitas — menukar implementasi melalui konfigurasi
Ini selaras dengan praktik terbaik inversion of control dan menghasilkan sistem yang lebih jelas dan mudah dipelihara7.
Pabrik
Pola Factory memusatkan logika pembuatan. Sebuah pabrik dapat mengembalikan instans yang sama atau instans baru sesuai kebutuhan. Kode klien meminta objek dari pabrik tanpa mengetahui bagaimana objek itu dibuat, yang menjaga kode tetap modular dan dapat diuji.
Instans Berlingkup
Terkadang Anda membutuhkan satu instans, tetapi hanya dalam lingkup terbatas (request, session, atau aplikasi). Framework mendukung bean dengan scope request atau session untuk memberikan keseimbangan antara penggunaan ulang sumber daya dan isolasi.
Singletons dalam Sistem Terdistribusi
Singleton yang lokal di JVM tidak memberikan Anda instans tunggal di seluruh banyak instance layanan. Microservices menjalankan banyak JVM, jadi Anda memerlukan solusi terdistribusi untuk state bersama, seperti Redis atau layanan konfigurasi terpusat seperti Consul atau Spring Cloud Config6.
Cara Merefactor Singleton dari Kode Legacy

Merefactor Singleton membutuhkan kehati-hatian. Masalah inti adalah ketergantungan langsung pada panggilan statis getInstance(). Pendekatan bertahap dan metodis mengurangi risiko.
Strategi langkah-demi-langkah:
- Perkenalkan sebuah antarmuka yang menggambarkan metode publik Singleton, dan biarkan Singleton mengimplementasikannya.
- Buat dependensi menjadi eksplisit dengan menambahkan parameter konstruktor pada kelas yang menggunakan Singleton.
- Gunakan pabrik atau kontainer DI (Spring, Guice) untuk menyediakan implementasi sebagai instans yang dikelola.
- Gantikan panggilan Singleton.getInstance() dengan dependensi yang disuntikkan melalui konstruktor.
- Hapus kode spesifik Singleton setelah semua pemanggil menerima dependensi secara eksternal.
Manfaat: modularitas, kemampuan diuji, dan kejelasan yang meningkat. Merefactor Singletons mengubah basis kode yang kaku menjadi komponen yang fleksibel dan dapat diuji.
Pertanyaan yang Sering Diajukan
Apakah pola Singleton merupakan antipola?
Sering kali, ya. Singleton memperkenalkan state global dan ketergantungan yang ketat, yang mengurangi kemampuan diuji dan meningkatkan biaya pemeliharaan jangka panjang. Gunakan dengan hemat dan lebih baik utamakan DI atau instans berlingkup jika memungkinkan.
Bagaimana cara Singleton dapat dipecah di Java?
Refleksi dan serialisasi dapat membuat instans baru kecuali Anda secara eksplisit melindungi terhadapnya. Menggunakan enum untuk singleton menghindari jebakan ini3.
Apakah Singleton tepat untuk microservices?
Tidak. Singleton berskala JVM, jadi setiap instance layanan mendapatkan Singleton-nya sendiri. Untuk state bersama antar layanan, gunakan sistem terdistribusi seperti Redis atau layanan konfigurasi terpusat6.
Tiga ringkasan tanya-jawab singkat
T: Kapan saya harus menggunakan Singleton? A: Hanya ketika satu instans benar-benar mewakili sebuah sumber daya tunggal dan global dalam satu JVM dan tidak ada alternatif yang lebih baik. Pilih enum Singleton jika memang harus menggunakan.
T: Bagaimana cara membuat Singleton yang lazy dan aman-thread? A: Gunakan idiom Initialization-on-demand Holder (Bill Pugh) atau enum. Keduanya memberikan keamanan-thread dengan overhead minimal; enum juga melindungi terhadap masalah serialisasi dan refleksi23.
T: Apa yang harus saya gunakan selain Singleton untuk kemampuan diuji yang lebih baik? A: Gunakan Injeksi Dependensi, pabrik, atau instans berlingkup sehingga dependensi menjadi eksplisit dan mudah diganti dalam pengujian47.
AI menulis kode.Anda membuatnya bertahan.
Di era akselerasi AI, kode bersih bukan hanya praktik yang baik — ini adalah perbedaan antara sistem yang berkembang dan codebase yang runtuh di bawah beratnya sendiri.