目录
一、特点:
二、实现单例模式步骤
三、饿汉式
四、懒汉式
五、双重检查锁
六、静态内部类
七、枚举
八、大概被反序列化和反射破坏什么意思?
九、怎样解决呢?
一、特点:
- 唯一性,单例模式确保步伐中只有一个实例存在
- 节省内存开销,不用多次创建对象
二、实现单例模式步骤
- 私有化构造函数,防止外部实例化
- 提供公共获取单例对象的静态方法
三、饿汉式
饿汉式是什么?
指在类加载时就完成了初始化。
- public class Singleton {
- //创建一个静态的单例对象
- private static final Singleton instance = new Singleton();
- //私有化构造函数,防止外部实例化
- private Singleton(){}
- //提供公共的获取单例对象的静态方法
- public static Singleton getInstance(){
- return instance;
- }
- }
复制代码
- object Singleton {
- //Kotlin的object关键字自动实现了饿汉式单例
- }
-
复制代码 优点:是线程安全的,因为JVM在进行类加载的时间,会进行加锁,每个类只有一份class对象,然后类加载的时间就会实验静态代码块、静态变量。
缺点:大概被反序列化和反射破坏、浪费资源,当你不需要单例实例,只想调用类中的静态方法时,它都会帮你实验静态代码块和静态变量,因为类加载。比方:
四、懒汉式
懒汉式是什么?
是指第一次调用时才初始化
1.不正确的懒汉式单例模式:
固然末了打印的效果是一样的对象,这是只有主线程的环境,但是如果在多线程下呢?
java例子:
koltin例子:
可以看到如果在多线程下,该对象就会被创建多次,以是这种方法是不对的。
2.正确的懒汉式单例模式:
- public class Singleton {
- //创建一个静态的单例对象
- private static Singleton instance = null;
- //私有化构造函数,防止外部实例化
- private Singleton(){
- System.out.println("Singleton正在实例化");
- }
- //提供公共的获取单例对象的静态方法
- public synchronized static Singleton getInstance(){
- if(instance == null){
- instance = new Singleton();
- }
- return instance;
- }
- }
复制代码
- class Singleton {
- private constructor(){
- println("Singleton正在被实例")
- }
- companion object{
- private var instance:Singleton? = null
- @Synchronized
- public fun getInstance():Singleton{
- if(instance == null){
- instance = Singleton()
- }
- return instance!!
- }
- }
- }
复制代码 优点:在多线程下,能包管该类只实例一次。
缺点:大概被反序列化和反射破坏、为方法加锁,粒度太大,即锁定的范围过宽。这意味着锁保护的区域较大,包罗了多个利用或整个方法,这会对系统的性能和并发能力产生一些负面影响,多个线程大概因为需要访问一个被锁定的方法而排队期待,导致线程资源的低效使用。
进行优化,减小锁的范围:
五、双重检查锁
- public class Singleton {
- //创建一个静态的单例对象
- private volatile static Singleton instance = null;
- //私有化构造函数,防止外部实例化
- private Singleton(){
- System.out.println("Singleton正在实例化");
- }
- //提供公共的获取单例对象的静态方法
- public static Singleton getInstance(){
- if(instance == null){
- synchronized(Singleton.class) {
- if(instance == null) {
- instance = new Singleton();
- }
- }
- }
- return instance;
- }
- }
复制代码
- class Singleton {
- private constructor(){
- println("Singleton正在被实例")
- }
- companion object{
- @Volatile
- private var instance:Singleton? = null
- public fun getInstance():Singleton{
- if(instance == null){
- synchronized(Singleton::class.java) {
- if(instance == null) {
- instance = Singleton()
- }
- }
- }
- return instance!!
- }
- }
- }
复制代码 优点:线程安全、进步了性能、避免了资源浪费。
缺点:大概被反序列化和反射破坏、结构复杂,要记得加volatile关键字。
六、静态内部类
- public class Singleton {
- //私有化构造函数,防止外部实例化
- private Singleton(){
- System.out.println("Singleton正在实例化");
- }
- // 静态内部类,只有在第一次被访问时才会被加载
- private static class SingletonHolder {
- private static final Singleton INSTANCE = new Singleton();
- }
- public static Singleton getInstance() {
- return SingletonHolder.INSTANCE;
- }
-
- }
复制代码
- class Singleton {
- private constructor(){
- println("Singleton正在被实例")
- }
- companion object{
- object SingletonHolder{
- val INSTANCE = Singleton()
- }
-
- public fun getInstance():Singleton{
- return SingletonHolder.INSTANCE
- }
- }
- }
复制代码 优点:线程安全、避免了资源浪费、实现简朴
缺点:大概被反序列化和反射破坏、它的线程安全是依靠类加载,但是类加载是耗性能的,类加载的过程:
七、枚举
- public enum Singleton {
- INSTANCE;
-
- // 可以在这里添加其他方法和属性
- }
复制代码
- enum class Singleton {
- INSTANCE;
-
- // 可以在这里添加其他方法和属性
- }
复制代码 优点:代码写法简便优雅、线程安全(通过反编译class文件,可以看到INSTANCE是一个静态变量。那么就是通过类加载来包管线程安全的)、可以防止反序列化和反射破坏单例、并且不用手动私有化构造函数。
缺点:不能继承别的类,因为它内部已经继承了Enum类、它的线程安全是依靠类加载,但是类加载是耗性能的。
八、大概被反序列化和反射破坏什么意思?
1.反序列化破坏:将一个单例对象进行序列化后,再反序列化,而反序列化的对象和步伐对象不是同一个对象。除了枚举的单例,别的的方式都会被反序列化破坏。
比方,以饿汉式为例子:
2.反射破坏:通过反射调用类的无参构造函数进行创建出来对象和步伐的单例对象不是同一个对象。除了枚举的单例,别的的方式都会被反射破坏
比方,以饿汉式为例子:
3.看看枚举的例子:
反射创建对象,直接报错:
序列化和反序列化不会破坏对象:
九、怎样解决呢?
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |