网站备案过期,网站源代码生成网站,公司注册地址异常,米粒网站建设单例模式即代码中只有一个实例的模式
适用场景#xff1a;有些场景下#xff0c;有的类只能有一个对象#xff0c;不能有多个
要注意#xff1a;在单例模式下#xff0c;要保证不能产生多个实例
1、饿汉模式
class Singleton{private static Singleton instance new …单例模式即代码中只有一个实例的模式
适用场景有些场景下有的类只能有一个对象不能有多个
要注意在单例模式下要保证不能产生多个实例
1、饿汉模式
class Singleton{private static Singleton instance new Singleton();public static Singleton getSingleton() {return instance;}private Singleton(){}
}public class demo {public static void main(String[] args) {Singleton singleton1 Singleton.getSingleton();Singleton singleton2 Singleton.getSingleton();System.out.println(singleton1singleton2);System.out.println(singleton1.equals(singleton2));}
}将构造方法设为private使得不能自己初始化类 只能用默认给定的类
由于是单例所以singleton1与singleton2地址内容都是一样的两者是同一个实例 2、 懒汉模式
1懒汉模式-不安全
class SingletonLazy{private static SingletonLazy instance null;public static SingletonLazy getSingletonLazy() {if(instance null){instance new SingletonLazy();}return instance;}private SingletonLazy(){}
}public class demo {public static void main(String[] args) {SingletonLazy singletonLazy1 SingletonLazy.getSingletonLazy();SingletonLazy singletonLazy2 SingletonLazy.getSingletonLazy();System.out.println(singletonLazy1 singletonLazy2);System.out.println(singletonLazy1.equals(singletonLazy2));}
}饿汉模式中无论原来有没有创建instance都会初始化一个新的instance
懒汉模式为了节约开销会在getSingletonLazy()方法中判断instance是否是null。如果不是null说明instance已经初始化只须直接返回即可如果是第一次获取那么instance没有初始化是null这时初始化后再返回
2懒汉模式-线程安全
上面的代码存在的问题是由于判断if(instance null)这一步和初始化instance new SingletonLazy()这一步是分开的有可能会出现线程安全问题
如上图T1和T2都各创建了一个instance实例从而出现了两个实例破坏了单例模式的规则
为了解决上述线程安全问题我们在getSingletonLazy()方法中对这段代码进行加锁静态方法代码块加锁对象用类名.class
public static SingletonLazy getInstance() {synchronized (SingletonLazy.class){if(instance null){instance new SingletonLazy();}}return instance;}
3空间浪费
改成加锁代码后产生了一个新问题那就是每次获得instance时都要进行加锁但是加锁本身是一项耗费空间资源的操作这样便会大大降低代码性能
如果我们能够得知实例已经创建那么就不用再进行加锁了所以在加锁之前我们对instance进行一次判断
public static SingletonLazy getInstance() {if(instance null){synchronized (SingletonLazy.class){if(instance null){instance new SingletonLazy();}}}return instance;
}
注意第一次判断和第二次判断作用并不一样第一次是为了判断是否需要加锁第二次是为了判断是否需要新创建实例
4指令重排序问题
经过两次优化上述代码仍存在问题那就是——指令重排序问题 · 什么是指令重排序问题呢
当我们在new一个对象的时候new这个过程分为三步 1.申请内存空间 2.在内存空间上构造对象 (构造方法) 3.把内存的地址,赋值给 instance 引用 这个过程可以按照123来执行也可以按照132的顺序来执行 在我们上述优化过的代码中如果T1线程在new的过程中按照132的顺序来执行那么在执行到第二步时恰好T2第一次对instance进行判断由于instance已经创建了实例那么T2会直接返回这个没有构造对象的instance
如果代码中对返回的instance进行访问属性/方法等操作程序就会报错 · volatile
为了解决这个问题我们使用了volatile关键字来对instance变量进行修饰
这样在进行new操作时就不会产生指令重排序问题
class SingletonLazy{private static volatile SingletonLazy instance null;public static SingletonLazy getInstance() {if (instance null){synchronized (SingletonLazy.class){if (instance null){instance new SingletonLazy();}}}return instance;}private SingletonLazy(){}
}
volatile解决内存可见性问题