konsep:
Pola singleton di java adalah pola desain yang umum. Pola singleton dibagi menjadi tiga jenis: Lazy Singleton, Hungry Singleton, dan terdaftar Singleton.
Mode singleton memiliki karakteristik berikut:
1. Hanya ada satu contoh di kelas singleton.
2. Kelas Singleton harus membuat contoh uniknya sendiri.
3. Kelas Singleton harus memberikan contoh ini kepada semua objek lain.
Pola Singleton memastikan bahwa suatu kelas hanya memiliki satu contoh, dan membuat instansi itu sendiri dan memberikan contoh ini ke seluruh sistem. Dalam sistem komputer, objek driver untuk kumpulan utas, cache, objek log, kotak dialog, printer, dan kartu grafis sering dirancang sebagai singleton. Aplikasi ini memiliki lebih atau kurang fungsionalitas manajer sumber daya. Setiap komputer dapat memiliki beberapa printer, tetapi hanya satu spooler printer yang dapat tersedia untuk menghindari dua pekerjaan cetak yang menghasilkan printer pada saat yang sama. Setiap komputer dapat memiliki beberapa port komunikasi, dan sistem harus mengelola port komunikasi ini secara terpusat untuk menghindari satu port komunikasi yang disebut secara bersamaan dengan dua permintaan. Singkatnya, memilih model singleton adalah untuk menghindari negara -negara yang tidak konsisten dan menghindari bullish politik.
Berikut adalah dua jenis perkenalan: malas dan lapar
1. Muat segera/gaya lapar
Sebelum memanggil metode, instance telah dibuat, kode:
Paket com.weishiyao.learn.day8.singleton.ep1; kelas publik myObject {// memuat sekarang == mode jahat private static myobject myObject = myobject baru (); private myObject () {} public static myObject getInstance () {// Versi kode ini memuat sekarang // kerugian dari versi kode ini adalah bahwa tidak mungkin variabel instance lain // karena metode getInstance () tidak disinkronkan // Oleh karena itu, masalah non-thread-safe dapat terjadi pengembalian myObject; }} Buat kelas utas
Paket com.weishiyao.learn.day8.singleton.ep1; kelas publik mythread memperluas utas {@override public void run () {System.out.println (myobject.getInstance (). hashcode ()); }} Buat Kelas Jalankan
paket com.weishiyao.learn.day8.singleton.ep1; kelas publik run {public static void main (string [] args) {mythread t1 = mythread baru (); Mythread t2 = mythread baru (); Mythread t3 = mythread baru (); t1.start (); t2.start (); t3.start (); }} Hasil berjalan
167772895
167772895
167772895
HashCode adalah nilai yang sama, yang berarti bahwa objek juga sama, yang berarti bahwa mode pemuatan instan diimplementasikan.
2. Pemuatan malas/malas
Contoh akan dibuat setelah metode dipanggil. Rencana implementasi dapat menempatkan instantiasi ke dalam konstruktor tanpa parameter, sehingga instance dari objek akan dibuat hanya ketika metode dipanggil. Kode:
Paket com.weishiyao.learn.day8.singleton.ep2; kelas publik myObject {private static myobject myObject; private myobject () {} public static myObject getInstance () {// tunda memuat if (myobject! = null) {} else {myobject = new myobject (); } return myObject; }} Buat kelas utas
Paket com.weishiyao.learn.day8.singleton.ep2; mythread kelas publik memperluas utas {@override public void run () {system.out.println (myobject.getInstance (). hashcode ()); }} Buat Kelas Jalankan
Paket com.weishiyao.learn.day8.singleton.ep2; kelas publik run {public static void main (string [] args) {mythread t1 = mythread baru (); t1.start (); }}Hasil berjalan
167772895
Meskipun sebuah instance dari suatu objek diambil, jika berada di lingkungan multi-threaded, beberapa instance akan terjadi, yang bukan pola singleton
Jalankan kelas tes
Paket com.weishiyao.learn.day8.singleton.ep2; kelas publik run {public static void main (string [] args) {mythread t1 = mythread baru (); Mythread t2 = mythread baru (); Mythread t3 = mythread baru (); Mythread t4 = mythread baru (); Mythread t5 = mythread baru (); t1.start (); t2.start (); t3.start (); t4.start (); t5.start (); }}Hasil berjalan
980258163
1224717057
1851889404
188820504
1672864109
Karena ada masalah, kita perlu menyelesaikan masalah. Solusi multithreaded dalam mode malas, kode:
Solusi pertama, paling umum, tambahkan disinkronkan, dan disinkronkan dapat ditambahkan ke posisi yang berbeda
Metode pertama mengunci
Paket com.weishiyao.learn.day8.singleton.ep3; kelas publik myObject {private static myobject myObject; private myObject () {} public static myObject getInstance (// tunda memuat cobalah {if (myObject! = null) {} else {// simulasikan beberapa persiapan sebelum membuat objek thread.sleep (2000); myObject = myObject baru (); }} catch (InterruptedException e) {E.PrintStackTrace (); } return myObject; }}Skema sinkronisasi yang disinkronkan ini menghasilkan terlalu tidak efisien dan seluruh metode terkunci
Skema penggunaan yang disinkronkan kedua
Paket com.weishiyao.learn.day8.singleton.ep3; kelas publik myObject {private static myobject myObject; private myobject () {} public static myObject getInstance () {// tunda memuat coba {disinkronkan (myobject.class) {if (myobject! = null) {} else {// simulasikan beberapa pekerjaan persiapan sebelum membuat objek thread.sleep (2000); myObject = myObject baru (); }}} catch (InterruptedException e) {E.PrintStackTrace (); } return myObject; }} Metode ini juga sangat efisiensi rendah. Semua kode dalam metode ini dikunci. Anda hanya perlu mengunci kode kunci. Rencana Penggunaan Sinkronisasi Ketiga
paket com.weishiyao.learn.day8.singleton.ep3;
kelas publik myObject {private static myObject myObject; private myobject () {} public static myObject getInstance () {// tunda memuat coba {if (myObject! = null) {} else {// simulasikan beberapa persiapan sebelum membuat objek thread.sleep (2000); disinkronkan (myobject.class) {myobject = new myobject (); }}} catch (InterruptedException e) {E.PrintStackTrace (); } return myObject; }}Ini tampaknya menjadi solusi terbaik, tetapi setelah menjalankannya, saya menemukan bahwa itu sebenarnya tidak aman
hasil:
1224717057
971173439
1851889404
1224717057
1672864109
Mengapa?
Meskipun pernyataan yang membuat objek terkunci, hanya satu utas yang dapat menyelesaikan kreasi sekaligus, setelah utas pertama masuk untuk membuat objek objek, utas kedua masih dapat terus membuatnya, karena kami hanya mengunci pernyataan pembuatan, solusi masalah ini ini
Paket com.weishiyao.learn.day8.singleton.ep3; kelas publik myObject {private static myobject myObject; private myobject () {} public static myObject getInstance () {// tunda memuat coba {if (myObject! = null) {} else {// simulasikan beberapa persiapan sebelum membuat objek thread.sleep (2000); disinkronkan (myobject.class) {if (myobject == null) {myobject = new myobject (); }}}} catch (InterruptedException e) {E.PrintStackTrace (); } return myObject; }}Cukup tambahkan penilaian lain ke kunci untuk memastikan singleton. Ini adalah mekanisme pemeriksaan ganda DCL
Hasilnya adalah sebagai berikut:
1224717057
1224717057
1224717057
1224717057
1224717057
3. Gunakan kelas statis bawaan untuk mengimplementasikan kasus tunggal
Kode utama
Paket com.weishiyao.learn.day8.singleton.ep4; kelas publik myObject {// Metode kelas dalam private static class myobjecthandler {private static myobject myobject = myobject (); } public myobject () {} public static myObject getInstance () {return myobjecthandler.myobject; }} Kode kelas utas
Paket com.weishiyao.learn.day8.singleton.ep4; mythread kelas publik memperluas thread {@override public void run () {System.out.println (myobject.getInstance (). hashcode ()); }} Jalankan kelas
paket com.weishiyao.learn.day8.singleton.ep4; kelas publik run {public static void main (string [] args) {mythread t1 = mythread baru (); Mythread t2 = mythread baru (); Mythread t3 = mythread baru (); Mythread t4 = mythread baru (); Mythread t5 = mythread baru (); t1.start (); t2.start (); t3.start (); t4.start (); t5.start (); }}hasil
1851889404
1851889404
1851889404
1851889404
1851889404
Melalui kelas statis internal, pola singleton yang aman dan aman diperoleh
Iv. Serialize dan deserialize pola singleton
Kelas statis bawaan dapat mencapai masalah keamanan utas, tetapi jika Anda menemukan objek serial, hasil yang diperoleh dengan menggunakan metode default masih banyak kasus.
Kode myObject
Paket com.weishiyao.learn.day8.singleton.ep5; import java.io.serializable; kelas publik myObject mengimplementasikan serializable { / ** * * / private static final long serialVersionuid = 888L; // Metode Kelas Dalam Private Static Class Myobjecthandler {private static myobject myObject = new myobject (); } public myobject () {} public static myObject getInstance () {return myobjecthandler.myobject; } // Protected myObject readResolve () {// system.out.println ("Metode readResolve dipanggil!"); // return myobjecthandler.myobject; //}} Bisnis
Paket com.weishiyao.learn.day8.singleton.ep5; impor java.io.file; impor java.io.fileinputStream; impor java.io.filenotfoundException; impor java.fileoutputstream; impor java.io.ioException; java.io.objectOutputStream; kelas publik Saveandread {public static void main (string [] args) {coba {myobject myobject = myobject.getInstance (); FileOutputStream fosRef = new FileOutputStream (file baru ("myobjectfile.txt")); ObjectOutputStream oosref = ObjectOutputStream baru (fosref); oosref.writeObject (myObject); oosref.close (); fosref.close (); System.out.println (myobject.hashcode ()); } catch (FileNotFoundException e) {e.printstacktrace (); } catch (ioException e) {e.printstacktrace (); } FileInputStream fisref; coba {fisref = fileInputStream baru (file baru ("myobjectfile.txt")); ObjectInputStream IOSREF = ObjectInputStream baru (fisref); MyObject myObject = (myObject) iosref.readObject (); iosref.close (); fisref.close (); System.out.println (myobject.hashcode ()); } catch (FileNotFoundException e) {e.printstacktrace (); } catch (ioException e) {e.printstacktrace (); } catch (ClassNotFoundException e) {E.PrintStackTrace (); }}}hasil
970928725
1099149023
Dua kode hash yang berbeda membuktikan bahwa mereka bukan objek yang sama. Solusi, tambahkan kode berikut
terlindungi myObject readResolve () {System.out.println ("Metode ReadResolve dipanggil!"); return myobjecthandler.myobject; }Dipanggil selama deserialisasi, Anda bisa mendapatkan objek yang sama
System.out.println (myobject.readResolve (). HashCode ());
hasil
1255301379
Metode ReadResolve dipanggil!
1255301379
Kode hash yang sama membuktikan bahwa objek yang sama diperoleh
5. Gunakan blok kode statis untuk mengimplementasikan kasus tunggal
Kode dalam blok kode statis sudah dieksekusi saat menggunakan kelas, sehingga fitur kode statis cepat dapat digunakan untuk mengimplementasikan mode laba sederhana.
Kelas myObject
Paket com.weishiyao.learn.day8.singleton.ep6; kelas publik myObject {private static myobject instance = null; private myobject () {super (); } static {instance = new myobject (); } public static myObject getInstance () {return instance; }} Kelas utas
Paket com.weishiyao.learn.day8.singleton.ep6; kelas publik mythread memperluas utas {@override public void run () {for (int i = 0; i <5; i ++) {System.out.println (myObject.getInstance (). hashcode ()); }}} Jalankan kelas
Paket com.weishiyao.learn.day8.singleton.ep6; kelas publik run {public static void main (string [] args) {mythread t1 = mythread baru (); Mythread t2 = mythread baru (); Mythread t3 = mythread baru (); Mythread t4 = mythread baru (); Mythread t5 = mythread baru (); t1.start (); t2.start (); t3.start (); t4.start (); t5.start (); }}Hasil Menjalankan:
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
Pola singleton yang aman-aman berhasil diperoleh melalui fitur hanya mengeksekusi blok kode statis sekali.
6. Gunakan tipe data enum enum untuk mengimplementasikan mode singleton
Karakteristik enum enum dan blok kode statis serupa. Saat menggunakan enum, konstruktor akan dipanggil secara otomatis dan juga dapat digunakan untuk mengimplementasikan mode singleton.
Kelas myObject
Paket com.weishiyao.learn.day8.singleton.ep7; impor java.sql.connection; impor java.sql.drivermanager; impor java.sql.sqlexception; public enum myObject {connectionFactory; koneksi koneksi pribadi; private myObject () {try {System.out.println ("Konstruksi myObject disebut"); String url = "jdbc: mysql: //172.16.221.19: 3306/weChat_1? UseUnicode = true & characterencoding = UTF-8"; String name = "root"; String password = "111111"; String driverName = "com.mysql.jdbc.driver"; Class.forname (drivername); koneksi = driverManager.getConnection (url, nama, kata sandi); } catch (ClassNotFoundException e) {E.PrintStackTrace (); } catch (sqlexception e) {e.printstacktrace (); }} koneksi publik getConnection () {return connection; }} Kelas utas
Paket com.weishiyao.learn.day8.singleton.ep7; kelas publik mythread memperluas utas {@override public void run () {for (int i = 0; i <5; i ++) {System.out.println (myObject.connectionFactory.getConnection (). Hashcode (). }}} Jalankan kelas
paket com.weishiyao.learn.day8.singleton.ep7; kelas publik run {public static void main (string [] args) {mythread t1 = mythread baru (); Mythread t2 = mythread baru (); Mythread t3 = mythread baru (); Mythread t4 = mythread baru (); Mythread t5 = mythread baru (); t1.start (); t2.start (); t3.start (); t4.start (); t5.start (); }}Hasil berjalan
Disebut myObject construct
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
Metode penulisan di atas memperlihatkan kelas enumerasi, yang melanggar "prinsip tanggung jawab tunggal". Anda dapat menggunakan kelas untuk membungkus enumerasi.
Paket com.weishiyao.learn.day8.singleton.ep8; impor java.sql.connection; import java.sql.driverManager; import java.sql.sqlexception; kelas publik myObject {public myenumsingleton {connectionFactory; koneksi koneksi pribadi; private myenumsingleton () {coba {System.out.println ("Konstruksi myObject disebut"); String url = "jdbc: mysql: //172.16.221.19: 3306/weChat_1? UseUnicode = true & characterencoding = UTF-8"; String name = "root"; String password = "111111"; String driverName = "com.mysql.jdbc.driver"; Class.forname (drivername); koneksi = driverManager.getConnection (url, nama, kata sandi); } catch (ClassNotFoundException e) {E.PrintStackTrace (); } catch (sqlexception e) {e.printstacktrace (); }} koneksi publik getConnection () {return connection; }} public static Connection getConnection () {return myenumsingleton.connectionFactory.getConnection (); }} Ubah kode utas
Paket com.weishiyao.learn.day8.singleton.ep8; kelas publik mythread memperluas utas {@override public void run () {for (int i = 0; i <5; i ++) {System.out.println (myObject.getConnection (). hashcode ()); }}} Akibatnya, konstruk myObject disebut
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
Di atas merangkum berbagai situasi dan solusi yang dihadapi ketika menggabungkan mode kepentingan tunggal dengan multi-threading, sehingga dapat ditinjau ketika digunakan nanti.