Apa cara yang efisien untuk menerapkan pola tunggal di Jawa?
java
singleton
design-patterns
Riyaz Mohammed Ibrahim
sumber
sumber
Jawaban:
Gunakan enum:
Joshua Bloch menjelaskan pendekatan ini dalam pidatonya di Java Reloaded di Google I / O 2008: tautan ke video . Lihat juga slide 30-32 dari presentasinya ( effective_java_reloaded.pdf ):
Edit: Sebuah porsi online "Efektif Jawa" kata:
sumber
Bergantung pada penggunaannya, ada beberapa jawaban "benar".
Karena java5 cara terbaik untuk melakukannya adalah dengan menggunakan enum:
Sebelum java5, kasus paling sederhana adalah:
Mari kita bahas kodenya. Pertama, Anda ingin kelas menjadi final. Dalam hal ini, saya telah menggunakan
final
kata kunci untuk memberi tahu pengguna bahwa itu final. Maka Anda perlu menjadikan konstruktor sebagai pribadi untuk mencegah pengguna membuat Foo mereka sendiri. Melempar pengecualian dari konstruktor mencegah pengguna untuk menggunakan refleksi untuk membuat Foo kedua. Kemudian Anda membuatprivate static final Foo
bidang untuk menampung satu-satunya contoh, danpublic static Foo getInstance()
metode untuk mengembalikannya. Spesifikasi Java memastikan bahwa konstruktor hanya dipanggil ketika kelas pertama kali digunakan.Ketika Anda memiliki objek yang sangat besar atau kode konstruksi yang berat DAN juga memiliki metode atau bidang statis yang dapat diakses lainnya yang mungkin digunakan sebelum instance diperlukan, maka dan hanya dengan demikian Anda perlu menggunakan inisialisasi malas.
Anda dapat menggunakan a
private static class
untuk memuat instance. Kode tersebut kemudian akan terlihat seperti:Karena baris
private static final Foo INSTANCE = new Foo();
hanya dieksekusi ketika kelas FooLoader benar-benar digunakan, ini menangani instantiation yang malas, dan apakah dijamin aman untuk thread.Ketika Anda juga ingin dapat membuat serial objek Anda, Anda perlu memastikan deserialisasi tidak akan membuat salinan.
Metode ini
readResolve()
akan memastikan satu-satunya instance akan dikembalikan, bahkan ketika objek itu serial dalam menjalankan program Anda sebelumnya.sumber
Penafian: Saya baru saja merangkum semua jawaban yang luar biasa dan menuliskannya dalam kata-kata saya.
Saat menerapkan Singleton, kami memiliki 2 opsi
1. Pemuatan malas
2. Pemuatan awal
Pemuatan malas menambah bit overhead (banyak yang harus jujur) jadi gunakanlah hanya ketika Anda memiliki objek yang sangat besar atau kode konstruksi yang berat DAN juga memiliki metode atau bidang statis yang dapat diakses lainnya yang mungkin digunakan sebelum sebuah instance dibutuhkan, kemudian dan hanya kemudian Anda perlu menggunakan inisialisasi malas. Selain itu memilih pemuatan awal adalah pilihan yang baik.
Cara paling sederhana untuk mengimplementasikan Singleton adalah
Semuanya baik kecuali singleton yang dimuat awal. Mari kita coba tunggal dimuat malas
Sejauh ini bagus tapi pahlawan kita tidak akan bertahan saat bertarung sendirian dengan banyak utas jahat yang menginginkan banyak contoh pahlawan kita. Jadi mari kita lindungi dari kejahatan multi threading
tapi itu tidak cukup untuk melindungi pahlawan, Sungguh !!! Ini adalah yang terbaik yang bisa kita lakukan untuk membantu pahlawan kita
Ini disebut "idiom Penguncian Ganda". Sangat mudah untuk melupakan pernyataan volatile dan sulit untuk memahami mengapa itu perlu.
Untuk detail: http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
Sekarang kita yakin tentang utas kejahatan tetapi bagaimana dengan serialisasi yang kejam? Kita harus memastikan walaupun de-serialiaztion tidak ada objek baru yang dibuat
Metode ini
readResolve()
akan memastikan satu-satunya instance akan dikembalikan, bahkan ketika objek itu serial dalam menjalankan program kami sebelumnya.Akhirnya kami telah menambahkan perlindungan yang cukup terhadap utas dan serialisasi tetapi kode kami terlihat besar dan jelek. Mari kita beri pahlawan kita make over
Ya, ini adalah pahlawan kami yang sama :)
Karena baris
private static final Foo INSTANCE = new Foo();
hanya dieksekusi ketika kelasFooLoader
benar-benar digunakan, ini menangani instantiation yang malas,dan apakah dijamin aman dari utas.
Dan kami telah sampai sejauh ini, di sini adalah cara terbaik untuk mencapai semua yang kami lakukan adalah cara terbaik
Yang secara internal akan diperlakukan seperti
Itu dia! Tidak ada lagi rasa takut serialisasi, utas dan kode jelek. ENUMS juga singleton diinisialisasi dengan malas .
-Joshua Bloch dalam "Java Efektif"
Sekarang Anda mungkin telah menyadari mengapa ENUM dianggap sebagai cara terbaik untuk menerapkan Singleton dan terima kasih atas kesabaran Anda :)
Diperbarui di blog saya .
sumber
serialVersionUID
dari0L
. Masalah ketiga: Tidak ada kustomisasi: Setiap writeObject khusus kelas, readObject, readObjectNoData, writeReplace, dan metode readResolve yang didefinisikan oleh tipe enum diabaikan selama serialisasi dan deserialisasi.Solusi yang diposting oleh Stu Thompson berlaku di Java5.0 dan yang lebih baru. Tapi saya lebih suka tidak menggunakannya karena saya pikir itu rawan kesalahan.
Sangat mudah untuk melupakan pernyataan volatile dan sulit untuk memahami mengapa itu perlu. Tanpa volatile kode ini tidak akan aman lagi karena antipattern penguncian diperiksa ulang. Lihat lebih lanjut tentang ini dalam paragraf 16.2.4 Java Concurrency in Practice . Singkatnya: Pola ini (sebelum Java5.0 atau tanpa pernyataan volatile) dapat mengembalikan referensi ke objek Bar yang (masih) dalam keadaan salah.
Pola ini diciptakan untuk optimalisasi kinerja. Tapi ini benar-benar bukan masalah nyata lagi. Kode inisialisasi malas berikut ini cepat dan - yang lebih penting - lebih mudah dibaca.
sumber
getBar()
. (Dan jikagetBar
disebut "terlalu dini" maka Anda akan menghadapi masalah yang sama tidak peduli bagaimana singleon diterapkan.) Anda dapat melihat pemuatan kelas yang malas dari kode di atas di sini: pastebin.com/iq2eayiRThread aman di Java 5+:
EDIT : Perhatikan
volatile
pengubah di sini. :) Ini penting karena tanpa itu, utas lainnya tidak dijamin oleh JMM (Java Memory Model) untuk melihat perubahan nilainya. Sinkronisasi tidak menangani hal itu - itu hanya membuat serialisasi akses ke blok kode itu.EDIT 2 : Jawaban @Bno merinci pendekatan yang direkomendasikan oleh Bill Pugh (FindBugs) dan dapat diperdebatkan dengan lebih baik. Baca dan ikutilah jawabannya.
sumber
Lupakan inisialisasi malas , itu terlalu bermasalah. Ini adalah solusi paling sederhana:
sumber
Pastikan Anda benar-benar membutuhkannya. Lakukan google untuk "anti-pola tunggal" untuk melihat beberapa argumen yang menentangnya. Saya kira tidak ada yang salah dengan itu tetapi itu hanya mekanisme untuk mengekspos beberapa sumber daya global / data jadi pastikan bahwa ini adalah cara terbaik. Secara khusus saya telah menemukan injeksi ketergantungan lebih berguna terutama jika Anda juga menggunakan tes unit karena DI memungkinkan Anda untuk menggunakan sumber daya yang diejek untuk tujuan pengujian.
sumber
Saya bingung dengan beberapa jawaban yang menyarankan DI sebagai alternatif untuk menggunakan lajang; ini adalah konsep yang tidak terkait. Anda dapat menggunakan DI untuk menyuntikkan instance tunggal atau non-tunggal (mis. Per-utas). Setidaknya ini benar jika Anda menggunakan Spring 2.x, saya tidak bisa berbicara untuk kerangka DI lainnya.
Jadi jawaban saya untuk OP adalah (dalam semua kecuali kode sampel yang paling sepele) untuk:
Pendekatan ini memberi Anda arsitektur terpisah yang bagus (dan karena itu fleksibel dan dapat diuji) di mana apakah menggunakan singleton adalah detail implementasi yang mudah dibalik (asalkan singlet yang Anda gunakan adalah threadsafe, tentu saja).
sumber
TicketNumberer
yang perlu memiliki contoh global tunggal, dan di mana Anda ingin menulis kelasTicketIssuer
yang berisi baris kodeint ticketNumber = ticketNumberer.nextTicketNumber();
. Dalam pemikiran tradisional tunggal, baris kode sebelumnya harus sepertiTicketNumberer ticketNumberer = TicketNumberer.INSTANCE;
. Dalam berpikir DI, kelas akan memiliki konstruktor sepertipublic TicketIssuer(TicketNumberer ticketNumberer) { this.ticketNumberer = ticketNumberer; }
.main
(atau salah satu anteknya) akan menciptakan ketergantungan dan kemudian memanggil konstruktor. Pada dasarnya, penggunaan variabel global (atau metode global) hanyalah bentuk sederhana dari pola locator layanan yang ditakuti , dan dapat diganti dengan injeksi dependensi, sama seperti penggunaan lain dari pola itu.Sangat pertimbangkan mengapa Anda membutuhkan singleton sebelum menulisnya. Ada perdebatan semu-religius tentang penggunaannya yang bisa dengan mudah Anda temukan jika Anda menggunakan google singleton di Jawa.
Secara pribadi saya mencoba menghindari lajang sesering mungkin karena berbagai alasan, lagi-lagi sebagian besar dapat ditemukan dengan googling lajang. Saya merasa bahwa sering lajang dilecehkan karena mereka mudah dipahami oleh semua orang, mereka digunakan sebagai mekanisme untuk memasukkan data "global" ke dalam desain OO dan mereka digunakan karena mudah untuk menghindari manajemen siklus hidup objek (atau benar-benar berpikir tentang bagaimana Anda dapat melakukan A dari dalam B). Lihatlah hal-hal seperti Inversion of Control (IoC) atau Dependency Injection (DI) untuk jalan tengah yang menyenangkan.
Jika Anda benar-benar membutuhkannya maka wikipedia memiliki contoh implementasi singleton yang tepat.
sumber
Berikut adalah 3 pendekatan berbeda
1) Enum
2) Pengecekan ganda Penguncian / pemuatan malas
3) Metode pabrik statis
sumber
Saya menggunakan Spring Framework untuk mengelola lajang saya. Itu tidak menegakkan "keanehan" kelas (yang sebenarnya tidak bisa Anda lakukan jika ada beberapa kelas loader yang terlibat) tetapi memberikan cara yang sangat mudah untuk membangun dan mengkonfigurasi pabrik yang berbeda untuk membuat berbagai jenis objek.
sumber
Wikipedia memiliki beberapa contoh lajang, juga di Jawa. Implementasi Java 5 terlihat cukup lengkap, dan aman untuk digunakan (diterapkan penguncian ganda).
sumber
Versi 1:
Pemuatan malas, aman dengan pemblokiran, kinerja rendah karena
synchronized
.Versi 2:
Pemuatan malas, aman dengan non-blocking, kinerja tinggi.
sumber
Jika Anda tidak perlu memuat malas maka cukup coba
Jika Anda ingin pemuatan yang malas dan Anda ingin Singleton Anda aman dari benang, coba pola periksa dua kali
Karena pola pemeriksaan ganda tidak dijamin berfungsi (karena beberapa masalah dengan kompiler, saya tidak tahu apa-apa lagi tentang itu.), Anda juga dapat mencoba menyinkronkan seluruh metode getInstance atau membuat registri untuk semua Singletons Anda.
sumber
volatile
Saya akan mengatakan Enum singleton
Singleton menggunakan enum di Jawa umumnya cara untuk mendeklarasikan enum singleton. Enum singleton dapat berisi variabel instan dan metode instance. Demi kesederhanaan, juga perhatikan bahwa jika Anda menggunakan metode instance apa pun dari yang Anda butuhkan untuk memastikan keamanan metode tersebut jika hal itu memengaruhi keadaan objek.
Penggunaan enum sangat mudah diimplementasikan dan tidak memiliki kelemahan tentang objek serial, yang harus dielakkan dengan cara lain.
Anda dapat mengaksesnya dengan
Singleton.INSTANCE
, lebih mudah daripada memanggilgetInstance()
metode di Singleton.Masalah lain dengan Singletons konvensional adalah bahwa begitu Anda mengimplementasikan
Serializable
antarmuka, Singleton tidak lagi tetap Singleton karenareadObject()
metode selalu mengembalikan contoh baru seperti konstruktor di Jawa. Ini dapat dihindari dengan menggunakanreadResolve()
dan membuang instance yang baru dibuat dengan mengganti dengan singleton seperti di bawah iniIni dapat menjadi lebih kompleks jika Kelas Singleton Anda mempertahankan keadaan, karena Anda perlu membuatnya sementara, tetapi dengan di Enum Singleton, Serialisasi dijamin oleh JVM.
Baca Bagus
sumber
sumber
Mungkin agak terlambat untuk permainan ini, tetapi ada banyak nuansa di sekitar menerapkan singleton. Pola dudukan tidak dapat digunakan dalam banyak situasi. Dan IMO saat menggunakan volatile - Anda juga harus menggunakan variabel lokal. Mari kita mulai dari awal dan beralih ke masalah. Anda akan melihat apa yang saya maksud.
Upaya pertama mungkin terlihat seperti ini:
Di sini kita memiliki kelas MySingleton yang memiliki anggota statis pribadi bernama INSTANCE, dan metode statis publik yang disebut getInstance (). Pertama kali getInstance () dipanggil, anggota INSTANCE adalah nol. Aliran kemudian akan jatuh ke dalam kondisi penciptaan dan membuat instance baru dari kelas MySingleton. Panggilan selanjutnya ke getInstance () akan menemukan bahwa variabel INSTANCE telah ditetapkan, dan karenanya tidak membuat instance MySingleton lain. Ini memastikan hanya ada satu instance MySingleton yang dibagikan di antara semua penelepon getInstance ().
Tetapi implementasi ini memiliki masalah. Aplikasi multi-utas akan memiliki kondisi balapan pada pembuatan instance tunggal. Jika beberapa utas eksekusi mengenai metode getInstance () pada (atau sekitar) pada waktu yang sama, mereka masing-masing akan melihat anggota INSTANCE sebagai nol. Ini akan menghasilkan setiap utas membuat instance MySingleton baru dan selanjutnya menetapkan anggota INSTANCE.
Di sini kami telah menggunakan kata kunci yang disinkronkan dalam tanda tangan metode untuk menyinkronkan metode getInstance (). Ini tentu akan memperbaiki kondisi balapan kami. Utas sekarang akan memblokir dan memasukkan metode satu per satu. Tetapi itu juga menciptakan masalah kinerja. Implementasi ini tidak hanya menyinkronkan pembuatan instance tunggal, tetapi juga menyinkronkan semua panggilan ke getInstance (), termasuk membaca. Membaca tidak perlu disinkronkan karena hanya mengembalikan nilai INSTANCE. Karena membaca akan menjadi bagian terbesar dari panggilan kami (ingat, instantiasi hanya terjadi pada panggilan pertama), kami akan mengalami performa yang tidak perlu dengan menyinkronkan seluruh metode.
Di sini kami telah memindahkan sinkronisasi dari tanda tangan metode, ke blok yang disinkronkan yang membungkus pembuatan instance MySingleton. Tetapi apakah ini menyelesaikan masalah kita? Ya, kami tidak lagi memblokir bacaan, tetapi kami juga telah mengambil langkah mundur. Beberapa utas akan menekan metode getInstance () pada atau sekitar waktu yang sama dan mereka semua akan melihat anggota INSTANCE sebagai nol. Mereka kemudian akan menekan blok yang disinkronkan di mana seseorang akan mendapatkan kunci dan membuat instance. Ketika utas itu keluar dari blok, utas lainnya akan bersaing untuk kunci, dan satu per satu setiap utas akan jatuh melalui blok dan membuat instance baru dari kelas kita. Jadi kami segera kembali ke tempat kami mulai.
Di sini kami mengeluarkan cek lain dari DALAM blok. Jika anggota INSTANCE telah ditetapkan, kami akan melewatkan inisialisasi. Ini disebut penguncian ganda.
Ini memecahkan masalah kami tentang banyak instantiasi. Tetapi sekali lagi, solusi kami telah menghadirkan tantangan lain. Utas lain mungkin tidak “melihat” bahwa anggota INSTANCE telah diperbarui. Ini karena bagaimana Java mengoptimalkan operasi memori. Utas menyalin nilai asli variabel dari memori utama ke dalam cache CPU. Perubahan nilai kemudian ditulis ke, dan dibaca dari, cache itu. Ini adalah fitur Java yang dirancang untuk mengoptimalkan kinerja. Tetapi ini menciptakan masalah bagi implementasi tunggal kami. Utas kedua - sedang diproses oleh CPU atau inti yang berbeda, menggunakan cache yang berbeda - tidak akan melihat perubahan yang dilakukan oleh yang pertama. Ini akan menyebabkan utas kedua melihat anggota INSTANCE sebagai nol yang memaksa instance baru singleton kami dibuat.
Kami menyelesaikan ini dengan menggunakan kata kunci yang tidak stabil pada pernyataan anggota INSTANCE. Ini akan memberi tahu kompiler untuk selalu membaca dari, dan menulis ke, memori utama, dan bukan cache CPU.
Tetapi perubahan sederhana ini harus dibayar. Karena kita mem-bypass cache CPU, kita akan mendapatkan hit kinerja setiap kali kita beroperasi pada anggota INSTANCE yang mudah menguap - yang kita lakukan 4 kali. Kami memeriksa ulang keberadaan (1 dan 2), mengatur nilai (3), dan kemudian mengembalikan nilai (4). Orang bisa berpendapat bahwa jalan ini adalah kasus pinggiran karena kami hanya membuat contoh selama panggilan pertama dari metode ini. Mungkin kinerja yang berhasil pada penciptaan bisa ditoleransi. Tetapi bahkan use case utama kita, berbunyi, akan beroperasi pada anggota volatile dua kali. Sekali untuk memeriksa keberadaan, dan lagi untuk mengembalikan nilainya.
Karena hit kinerja adalah karena beroperasi secara langsung pada anggota yang mudah menguap, mari kita tetapkan variabel lokal ke nilai yang tidak stabil dan beroperasi pada variabel lokal sebagai gantinya. Ini akan mengurangi berapa kali kami beroperasi pada volatile, sehingga mengambil kembali sebagian dari kinerja kami yang hilang. Perhatikan bahwa kita harus mengatur variabel lokal kita lagi ketika kita memasuki blok yang disinkronkan. Ini memastikan sudah mutakhir dengan perubahan apa pun yang terjadi saat kami sedang menunggu kunci.
Saya menulis artikel tentang ini baru-baru ini. Mendekonstruksi Singleton . Anda dapat menemukan lebih banyak info tentang contoh-contoh ini dan contoh pola "pemegang" di sana. Ada juga contoh dunia nyata yang menampilkan pendekatan volatil yang dicek ganda. Semoga ini membantu.
sumber
BearerToken instance
dalam artikel Anda tidakstatic
? Dan apa ituresult.hasExpired()
?class MySingleton
- mungkin seharusnyafinal
?BearerToken
tidak statis karena merupakan bagian dariBearerTokenFactory
- yang dikonfigurasi dengan server otorisasi tertentu. Mungkin ada banyakBearerTokenFactory
objek - masing-masing memiliki "cache" sendiri yang dibagikanBearerToken
sampai habis. ThehasExpired()
metode padaBeraerToken
disebut dalam pabrikget()
metode untuk memastikan tidak membagikan sebuah kadaluarsa tanda. Jika kedaluwarsa, token baru akan diminta dari server otorisasi. Paragraf yang mengikuti blok kode menjelaskan ini secara lebih rinci.Ini adalah cara mengimplementasikan yang sederhana
singleton
:Ini adalah cara membuat malas dengan benar
singleton
:sumber
getInstance()
. Tetapi memang jika Anda tidak memiliki metode statis lain di kelasSingleton
Anda dan Anda hanya menelepongetInstance()
tidak ada perbedaan nyata.Anda perlu memeriksa ulang idiom jika Anda perlu memuat variabel instan dari sebuah kelas. Jika Anda perlu memuat variabel statis atau tunggal dengan malas, Anda perlu inisilisasi pada idiom pemegang permintaan .
Selain itu, jika singleton perlu seriliazble, semua bidang lainnya harus bersifat sementara dan metode readResolve () perlu diimplementasikan untuk mempertahankan invarian objek singleton. Jika tidak, setiap kali objek di-deserialisasi, instance baru dari objek akan dibuat. Apa yang readResolve () lakukan adalah mengganti objek baru yang dibaca oleh readObject (), yang memaksa objek baru itu menjadi sampah yang dikumpulkan karena tidak ada variabel yang merujuk padanya.
sumber
Berbagai cara untuk membuat objek tunggal:
Sesuai Joshua Bloch - Enum akan menjadi yang terbaik.
Anda dapat menggunakan penguncian cek ganda juga.
Bahkan kelas statis dalam dapat digunakan.
sumber
Enum singleton
Cara paling sederhana untuk mengimplementasikan Singleton yang aman-threaded adalah menggunakan Enum
Kode ini berfungsi sejak diperkenalkannya Enum di Java 1.5
Penguncian diperiksa ganda
Jika Anda ingin kode singleton "klasik" yang berfungsi di lingkungan multithreaded (mulai dari Java 1.5) Anda harus menggunakan yang ini.
Ini tidak aman sebelum 1,5 karena penerapan kata kunci yang mudah menguap berbeda.
Pemuatan awal Singleton (bekerja bahkan sebelum Java 1.5)
Implementasi ini instantiates singleton ketika kelas dimuat dan memberikan keamanan thread.
sumber
Untuk JSE 5.0 dan di atasnya, gunakan pendekatan Enum, jika tidak gunakan pendekatan static singleton holder ((pendekatan lazy loading yang dijelaskan oleh Bill Pugh). Solusi terakhir juga aman untuk benang tanpa memerlukan konstruksi bahasa khusus (yaitu volatile atau disinkronkan).
sumber
Argumen lain yang sering digunakan terhadap Lajang adalah masalah testabilitas mereka. Lajang tidak mudah dipermainkan untuk tujuan pengujian. Jika ini ternyata menjadi masalah, saya ingin melakukan sedikit modifikasi berikut:
setInstance
Metode yang ditambahkan memungkinkan pengaturan implementasi mockup dari kelas singleton selama pengujian:Ini juga bekerja dengan pendekatan inisialisasi awal:
Ini memiliki kelemahan dalam mengekspos fungsi ini ke aplikasi normal juga. Pengembang lain yang mengerjakan kode itu bisa tergoda untuk menggunakan metode 'setInstance' untuk mengubah fungsi tertentu dan dengan demikian mengubah seluruh perilaku aplikasi, oleh karena itu metode ini harus mengandung setidaknya peringatan yang baik di javadoc-nya.
Namun, untuk kemungkinan pengujian-mockup (bila perlu), paparan kode ini mungkin merupakan harga yang dapat diterima untuk membayar.
sumber
kelas singleton paling sederhana
sumber
Saya masih berpikir setelah java 1.5, enum adalah implementasi singleton terbaik yang tersedia karena juga memastikan bahwa bahkan di lingkungan multi-threaded - hanya satu instance yang dibuat.
public enum Singleton{ INSTANCE; }
dan kamu selesai !!!
sumber
Lihat posting ini.
Contoh Pola Desain GoF di perpustakaan inti Jawa
Dari bagian "Singleton" jawaban terbaik,
Anda juga dapat mempelajari contoh Singleton dari kelas asli Jawa sendiri.
sumber
Pola singleton terbaik yang pernah saya lihat menggunakan antarmuka Pemasok.
Lihat di bawah:
sumber
Terkadang "
static Foo foo = new Foo();
" sederhana tidak cukup. Pikirkan beberapa penyisipan data dasar yang ingin Anda lakukan.Di sisi lain Anda harus menyinkronkan metode apa pun yang instantiates variabel singleton seperti itu. Sinkronisasi tidak seburuk itu, tetapi dapat menyebabkan masalah kinerja atau penguncian (dalam situasi yang sangat jarang menggunakan contoh ini. Solusinya adalah
Sekarang apa yang terjadi? Kelas dimuat melalui pemuat kelas. Langsung setelah kelas ditafsirkan dari byte Array, VM mengeksekusi blok {} - statis . itulah rahasianya: Blok-statis hanya dipanggil sekali, waktu kelas yang diberikan (nama) dari paket yang diberikan dimuat oleh loader satu kelas ini.
sumber
Karena kami telah menambahkan kata kunci yang Disinkronkan sebelum getInstance, kami telah menghindari kondisi balapan dalam kasus ketika dua utas memanggil getInstance secara bersamaan.
sumber