Ya, itu perlu. Ada beberapa metode yang dapat Anda gunakan untuk mencapai keamanan thread dengan inisialisasi yang lambat:
Sinkronisasi draconian:
private static YourObject instance;
public static synchronized YourObject getInstance() {
if (instance == null) {
instance = new YourObject();
}
return instance;
}
Solusi ini mengharuskan setiap utas disinkronkan ketika pada kenyataannya hanya beberapa utas yang perlu disinkronkan.
Periksa kembali sinkronisasi :
private static final Object lock = new Object();
private static volatile YourObject instance;
public static YourObject getInstance() {
YourObject r = instance;
if (r == null) {
synchronized (lock) { // While we were waiting for the lock, another
r = instance; // thread may have instantiated the object.
if (r == null) {
r = new YourObject();
instance = r;
}
}
}
return r;
}
Solusi ini memastikan bahwa hanya beberapa utas pertama yang mencoba memperoleh tunggal Anda yang harus melalui proses memperoleh kunci.
Inisialisasi sesuai Permintaan :
private static class InstanceHolder {
private static final YourObject instance = new YourObject();
}
public static YourObject getInstance() {
return InstanceHolder.instance;
}
Solusi ini memanfaatkan jaminan model memori Java tentang inisialisasi kelas untuk memastikan keamanan thread. Setiap kelas hanya dapat dimuat sekali, dan hanya akan dimuat saat diperlukan. Artinya, pertama kali getInstance
dipanggil, InstanceHolder
akan dimuat dan instance
akan dibuat, dan karena ini dikontrol oleh ClassLoader
s, tidak diperlukan sinkronisasi tambahan.
Draconian synchronization
danDouble check synchronization
getInstance () - metode harus statis!static
, tapi mungkin lebih masuk akal jika mereka. Diubah sesuai permintaan.r
tidak diperlukan untuk kebenaran. Ini hanya pengoptimalan untuk menghindari mengakses bidang volatile, karena itu jauh lebih mahal daripada mengakses variabel lokal.Pola ini melakukan inisialisasi lambat yang aman untuk instance tanpa sinkronisasi eksplisit!
Ini berfungsi karena ia menggunakan pemuat kelas untuk melakukan semua sinkronisasi untuk Anda secara gratis: Kelas
MySingleton.Loader
pertama kali diakses di dalamgetInstance()
metode, sehinggaLoader
kelas akan dimuat saatgetInstance()
dipanggil untuk pertama kali. Selanjutnya, pemuat kelas menjamin bahwa semua inisialisasi statis selesai sebelum Anda mendapatkan akses ke kelas - itulah yang memberi Anda keamanan thread.Ini seperti sulap.
Ini sebenarnya sangat mirip dengan pola enum Jhurtado, tapi saya menemukan pola enum merupakan penyalahgunaan konsep enum (meskipun itu berhasil)
sumber
final
harus ditambahkan. Selesai.Jika Anda bekerja pada lingkungan multithread di Java dan perlu menjamin semua utas tersebut mengakses satu instance kelas, Anda dapat menggunakan Enum. Ini akan memiliki keuntungan tambahan untuk membantu Anda menangani serialisasi.
dan kemudian minta utas Anda menggunakan contoh Anda seperti:
sumber
Ya, Anda perlu melakukan
getInstance()
sinkronisasi. Jika tidak, mungkin akan timbul situasi di mana beberapa contoh kelas dapat dibuat.Pertimbangkan kasus di mana Anda memiliki dua utas yang memanggil
getInstance()
pada saat yang bersamaan. Sekarang bayangkan T1 dijalankan setelahinstance == null
pemeriksaan, dan kemudian T2 berjalan. Pada titik ini, instance tidak dibuat atau disetel, jadi T2 akan lulus pemeriksaan dan membuat instance. Sekarang bayangkan eksekusi beralih kembali ke T1. Sekarang singleton telah dibuat, tetapi T1 telah melakukan pemeriksaan! Ini akan melanjutkan untuk membuat objek lagi! MembuatgetInstance()
sinkronisasi mencegah masalah ini.Ada beberapa cara untuk membuat lajang aman thread, tetapi membuat
getInstance()
sinkronisasi mungkin yang paling sederhana.sumber
Enum tunggal
Cara termudah untuk mengimplementasikan Singleton yang aman untuk thread menggunakan Enum
Kode ini berfungsi sejak diperkenalkannya Enum di Java 1.5
Penguncian diperiksa ganda
Jika Anda ingin membuat kode tunggal "klasik" yang berfungsi di lingkungan multithread (mulai dari Java 1.5), Anda harus menggunakan yang ini.
Ini bukan thread-safe sebelum 1.5 karena implementasi kata kunci volatile berbeda.
Pemuatan awal Singleton (bekerja bahkan sebelum Java 1.5)
Implementasi ini membuat instance tunggal saat kelas dimuat dan menyediakan keamanan thread.
sumber
Anda juga dapat menggunakan blok kode statis untuk membuat instance instance pada pemuatan kelas dan mencegah masalah sinkronisasi thread.
sumber
instance
final 2. Anda harus membuatgetInstance()
statis.Lihat posting ini untuk cara terbaik menerapkan Singleton.
Apa cara yang efisien untuk mengimplementasikan pola tunggal di Java?
Itu tergantung pada cara Anda mengimplementasikan metode. Jika Anda menggunakan penguncian ganda tanpa variabel volatile, Anda mungkin mendapatkan objek Singleton yang dibangun sebagian.
Lihat pertanyaan ini untuk lebih jelasnya:
Mengapa volatile digunakan dalam contoh penguncian centang ganda ini
Tidak diperlukan jika Anda mengimplementasikan Singleton dengan cara di bawah ini
Lihat pertanyaan ini untuk detail lebih lanjut
Pola Desain Java Singleton: Pertanyaan
sumber
Sumber: Java Efektif -> Item 2
Ini menyarankan untuk menggunakannya, jika Anda yakin bahwa kelas akan selalu tetap tunggal.
sumber