Bagaimana untuk menyelesaikan masalah keselamatan java singleton dan thread
Mod Singleton, mod berbilang contoh dan keselamatan benang
Mod Singleton
Mod Singleton merujuk kepada memastikan kelas hanya Ada ialah contoh yang unik dan menyediakan pusat akses global.
Kategori: Gaya Lelaki Malas, Gaya Lelaki Lapar
Mengapa anda memerlukan mod singleton?
Dalam beberapa kes khas, kelas hanya boleh digunakan untuk menjana objek unik. Contohnya: terdapat banyak pencetak di dalam bilik pencetak, tetapi sistem pengurusan cetakannya hanya mempunyai satu objek kawalan tugas cetakan, yang menguruskan baris gilir cetakan dan memberikan tugas cetakan kepada setiap pencetak. Corak tunggal dicipta untuk menyelesaikan keperluan tersebut.
Idea pelaksanaan:
Untuk mengelakkan klien daripada menggunakan pembina untuk mencipta berbilang objek, isytiharkan pembina sebagai jenis persendirian. Tetapi ini akan menjadikan kelas ini tidak tersedia, jadi kaedah statik yang boleh mendapatkan tika mesti disediakan, biasanya dipanggil kaedah getInstance, yang mengembalikan tika. Kaedah ini mestilah statik, kerana kaedah statik dipanggil berdasarkan nama kelas, jika tidak, kaedah ini tidak boleh digunakan.
Rajah kelas: Gaya Cina malas
Rajah kelas: Gaya Cina Lapar
Mari kita lihat contoh mudah dahulu:
Ujian kelas singleton: Dog’
//懒汉式 public class Dog { private static Dog dog; private String name; private int age; //私有的构造器 private Dog() {} public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } //静态工厂方法 public static Dog getInstance() { if (dog == null) { dog = new Dog(); } return dog; } @Override public String toString() { return "Dog [name=" + name + ", age=" + age + "]"; } }
Ujian kelas singleton : Kucing
//饿汉式 public class Cat { private static Cat cat = new Cat(); private String name; private int age; //私有构造器 private Cat() {} public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } //静态工厂方法 public static Cat getInstance() { return cat; } @Override public String toString() { return "Cat [name=" + name + ", age=" + age + "]"; } }
Kelas ujian
import java.util.HashSet; import java.util.Set; public class Client { public static void main(String[] args) { //单线程模式测试 Dog dog1 = Dog.getInstance(); Dog dog2 = Dog.getInstance(); System.out.println("dog1 == dog2: "+(dog1 == dog2)); Cat cat1 = Cat.getInstance(); Cat cat2 = Cat.getInstance(); System.out.println("cat1 == cat2: "+(cat1 == cat2)); } }
Hasil lari
Perbandingan antara gaya Cina malas dan gaya Cina lapar
Perbezaan ciptaan
Gaya Cina malas mencipta singleton apabila statikkaedah getInstance() dipanggil untuk objek kali pertama.
Gaya Lapar adalah untuk mencipta objek tunggal apabila kelas dimuatkan, iaitu, membuat instantiat kelas tunggal apabila mengisytiharkan objek tunggal statik.
Thread-safe
Gaya malas adalah benang-tidak selamat, manakala gaya lapar adalah thread-safe (akan diuji di bawah).
Pekerjaan sumber
Gaya malas dicipta apabila ia digunakan, manakala gaya lapar dicipta apabila kelas dimuatkan. Oleh itu, gaya orang malas tidak sepantas gaya orang lapar, tetapi gaya orang lapar mengambil lebih banyak sumber Jika ia tidak digunakan sepanjang masa, ia akan menduduki banyak sumber.
Keselamatan dalam mod berbilang benang
Kelas berbilang benang
import java.util.HashSet; import java.util.Set; public class DogThread extends Thread{ private Dog dog; private Set<Dog> set; public DogThread() { set = new HashSet<>(); } //这个方法是为了测试添加的。 public int getCount() { return set.size(); } @Override public void run() { dog = Dog.getInstance(); set.add(dog); } }
Kelas ujian berbilang benang
rreeeKeputusan berjalan
Nota: Keputusan berbilang benang adalah sukar untuk diramalkan di sini Keputusan mungkin sama berbilang kali tidak bermakna ia adalah sama) Betul sekali), tetapi selagi anda mengujinya beberapa kali, anda boleh melihat hasil yang berbeza.
Penjelasan
Di sini saya menggunakan teknik set sedikit, menggunakan Set Ciri-ciri koleksi adalah untuk menyimpan objek anjing yang dijana setiap kali dalam koleksi Set, dan akhirnya hanya memanggil kaedah saiz() koleksi. Ia boleh dilihat bahawa dua objek anjing dihasilkan, yang bermaksud ralat telah berlaku, iaitu ralat pengaturcaraan. Ia juga penting untuk memahami bahawa ralat mungkin tidak berlaku di bawah berbilang benang, jadi objek anjing yang dijana adalah lebih kecil daripada bilangan utas.
Memandangkan singleton ala Hungry adalah selamat untuk benang, ia tidak akan diuji di sini Jika anda berminat, anda boleh mengujinya.
Satu cara untuk menyelesaikan keselamatan benang bagi singleton yang malas: penyegerakan
Nota: Terdapat banyak kaedah penyegerakan, dan anda juga boleh menggunakan Lock untuk pemprosesan ialah kaedah , bukan yang khusus Mereka yang berminat boleh meneroka lebih lanjut tentang kata kunci yang disegerakkan.
Dan kaedah penyegerakan biasanya lebih perlahan dan perlu ditimbang dari segi prestasi.
import java.util.HashSet; import java.util.Set; public class Client { public static void main(String[] args) { //单线程模式测试 Dog dog1 = Dog.getInstance(); Dog dog2 = Dog.getInstance(); System.out.println("dog1 == dog2: "+(dog1 == dog2)); Cat cat1 = Cat.getInstance(); Cat cat2 = Cat.getInstance(); System.out.println("cat1 == cat2: "+(cat1 == cat2)); //多线程模式测试 DogThread dogThread = new DogThread(); Thread thread = null; for (int i = 0; i < 10; i++) { thread = new Thread(dogThread); thread.start(); } try { Thread.sleep(2000); //主线程等待子线程完成! } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("dog's number: "+dogThread.getCount()); } }
Mod berbilang tika
Berikut ialah mod berbilang tika, iaitu bilangan objek ialah nombor tetap. Anda boleh lihat promosi corak singleton. Sudah tentu, terdapat banyak cara untuk melaksanakannya. Anda boleh mencuba yang berikut.
Kelas mod berbilang contoh
//静态同步工厂方法 public synchronized static Dog getInstance() { if (dog == null) { dog = new Dog(); } return dog; }
Kelas ujian
//固定数目实例模式 public class MultiInstance { //实例数量,这里为四个 private final static int INSTANCE_COUNT = 4; private static int COUNT = 0; private static MultiInstance[] instance = new MultiInstance[4]; private MultiInstance() {}; public static MultiInstance getInstance() { //注意数组的下标只能为 COUNT - 1 if (MultiInstance.COUNT <= MultiInstance.INSTANCE_COUNT - 1) { instance[MultiInstance.COUNT] = new MultiInstance(); MultiInstance.COUNT++; } //返回实例前,执行了 COUNT++ 操作,所以 应该返回上一个实例 return MultiInstance.instance[MultiInstance.COUNT-1]; } }
Hasil berjalan
Nota : Jika digunakan dalam persekitaran berbilang benang, keselamatan benang juga mesti dipertimbangkan. Jika anda berminat, anda boleh melaksanakannya sendiri.
Adakah mod singleton semestinya selamat?
Tidak semestinya, terdapat banyak cara untuk memecahkan corak singleton!
这里举例看一看(我只能举我知道的哈!其他的感兴趣,可以去探究一下!)
使用反射:这种办法是非常有用的,通过反射即使是私有的属性和方法也可以访问了,因此反射破坏了类的封装性,所以使用反射还是要多多小心。但是反射也有许多其他的用途,这是一项非常有趣的技术(我也只是会一点点)。
使用反射破坏单例模式测试类
这里使用的还是前面的 Dog 实体类。注意我这里的**包名:**com。
所有的类都是在 com包 下面的。
import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; public class Client { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { Class<?> clazz = Class.forName("com.Dog"); Constructor<?> con = clazz.getDeclaredConstructor(); //设置可访问权限 con.setAccessible(true); Dog dog1 = (Dog) con.newInstance(); Dog dog2 = (Dog) con.newInstance(); System.out.println(dog1 == dog2); } }
说明:反射的功能是很强大的,从这里既可以看出来,正是有了反射,才使得Java 语言具有了更多的特色,这也是Java的强大之处。
使用对象序列化破坏单例模式
测试实体类:Dog(增加一个对象序列化接口实现)
import java.io.Serializable; //懒汉式 public class Dog implements Serializable{ private static final long serialVersionUID = 1L; private static Dog dog; private String name; private int age; //私有的构造器 private Dog() {} public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } //静态工厂方法 public synchronized static Dog getInstance() { if (dog == null) { dog = new Dog(); } return dog; } @Override public String toString() { return "Dog [name=" + name + ", age=" + age + "]"; } }
对象序列化测试类
import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class Client { public static void main(String[] args) throws IOException, ClassNotFoundException { Dog dog1 = Dog.getInstance(); dog1.setName("小黑"); dog1.setAge(2); System.out.println(dog1.toString()); ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(dog1); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); Dog dog2 = (Dog) ois.readObject(); System.out.println(dog2.toString()); System.out.println("dog1 == dog2: "+(dog1 == dog2)); } }
运行结果
说明
这里可以看出来通过对象序列化(这里也可以说是对象的深拷贝或深克隆),
同样也可以实现类的实例的不唯一性。这同样也算是破坏了类的封装性。对象序列化和反序列化的过程中,对象的唯一性变了。
这里具体的原因很复杂,我最近看了点深拷贝的知识,所以只是知其然不知其之所以然。(所以学习是需要不断进行的!加油诸位。)
这里我贴一下别的经验吧:(感兴趣的可以实现一下!)
为什么序列化可以破坏单例了?
答:序列化会通过反射调用无参数的构造方法创建一个新的对象。
这个东西目前超出了我的能力范围了,但也是去查看源码得出来的,就是序列化(serializable)和反序列化(externalizable)接口的详细情况了。但是有一点,它也是通过反射来做的的,所以可以看出**反射(reflect)**是一种非常强大和危险的技术了。
Atas ialah kandungan terperinci Bagaimana untuk menyelesaikan masalah keselamatan java singleton dan thread. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

AI Hentai Generator
Menjana ai hentai secara percuma.

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas



Panduan Nombor Sempurna di Jawa. Di sini kita membincangkan Definisi, Bagaimana untuk menyemak nombor Perfect dalam Java?, contoh dengan pelaksanaan kod.

Panduan untuk Weka di Jawa. Di sini kita membincangkan Pengenalan, cara menggunakan weka java, jenis platform, dan kelebihan dengan contoh.

Panduan untuk Nombor Smith di Jawa. Di sini kita membincangkan Definisi, Bagaimana untuk menyemak nombor smith di Jawa? contoh dengan pelaksanaan kod.

Dalam artikel ini, kami telah menyimpan Soalan Temuduga Spring Java yang paling banyak ditanya dengan jawapan terperinci mereka. Supaya anda boleh memecahkan temuduga.

Java 8 memperkenalkan API Stream, menyediakan cara yang kuat dan ekspresif untuk memproses koleksi data. Walau bagaimanapun, soalan biasa apabila menggunakan aliran adalah: bagaimana untuk memecahkan atau kembali dari operasi foreach? Gelung tradisional membolehkan gangguan awal atau pulangan, tetapi kaedah Foreach Stream tidak menyokong secara langsung kaedah ini. Artikel ini akan menerangkan sebab -sebab dan meneroka kaedah alternatif untuk melaksanakan penamatan pramatang dalam sistem pemprosesan aliran. Bacaan Lanjut: Penambahbaikan API Java Stream Memahami aliran aliran Kaedah Foreach adalah operasi terminal yang melakukan satu operasi pada setiap elemen dalam aliran. Niat reka bentuknya adalah

Panduan untuk TimeStamp to Date di Java. Di sini kita juga membincangkan pengenalan dan cara menukar cap waktu kepada tarikh dalam java bersama-sama dengan contoh.

Kapsul adalah angka geometri tiga dimensi, terdiri daripada silinder dan hemisfera di kedua-dua hujungnya. Jumlah kapsul boleh dikira dengan menambahkan isipadu silinder dan jumlah hemisfera di kedua -dua hujungnya. Tutorial ini akan membincangkan cara mengira jumlah kapsul yang diberikan dalam Java menggunakan kaedah yang berbeza. Formula volum kapsul Formula untuk jumlah kapsul adalah seperti berikut: Kelantangan kapsul = isipadu isipadu silinder Dua jumlah hemisfera dalam, R: Radius hemisfera. H: Ketinggian silinder (tidak termasuk hemisfera). Contoh 1 masukkan Jejari = 5 unit Ketinggian = 10 unit Output Jilid = 1570.8 Unit padu menjelaskan Kirakan kelantangan menggunakan formula: Kelantangan = π × r2 × h (4

Spring Boot memudahkan penciptaan aplikasi Java yang mantap, berskala, dan siap pengeluaran, merevolusi pembangunan Java. Pendekatan "Konvensyen Lebih Konfigurasi", yang wujud pada ekosistem musim bunga, meminimumkan persediaan manual, Allo
