单例模式确保每个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
获取单例时,不能产生多个实例对象;
使用单例时,注意单例对象内的实例变量会被多线程共享,会有线程安全问题。
无状态对象,阻塞式创建
' // 单例类
public class Singleton{ // 类的唯一实例,静态变量, final,没有线程安全问题 private final static Singleton instance = new Singleton(); private Singleton(){} public static Singleton getInstance(){ return instance; }}'
写法简单;类装载时完成实例化;避免线程同步问题。
'// 单例类
public class Singleton{ // 类的唯一实例,静态代码块处实例化,类装载时执行静态块初始实例 final,没有线程安全问题 private static Singleton instance; static{ instance = new Singleton(); } private Singleton(){} public static Singleton getInstance(){ return INSTANCE; }}'
' // 单例类
public class Singleton{ // 代码执行判断没有创建实例时创建唯一实例 final,没有线程安全问题 private static Singleton instance; private Singleton(){} public static Singleton getInstance(){ if(instance == null){ instance = new Singleton(); } return instance; }}'
懒加载,使用时,创建;
多线程下不能使用,多线程会创建多个实例,A进入if判断,未往下执行,B也判断。产生多个实例。
' // 单例类
public class Singleton{ // 代码执行判断没有创建实例时创建唯一实例 private static Singleton instance; private Singleton(){} public static synchronized Singleton getInstance(){ if(instance == null){ instance = new Singleton(); } return instance; }}'
对上一种的可能引发同步问题的方法加了sychronized上锁。
阻塞式同步。
效率低,每个线程想获得实例时,执行get都要同步,实际上实例化只要一次就行,获取直接return就好。
' // 单例类
public class Singleton{ // 代码执行判断没有创建实例时创建唯一实例 private static Singleton instance; private Singleton(){} public static Singleton getInstance(){ if(instance == null){ sychronized(Singleton.class){ instance = new Singleton(); } } return instance; }}'
无法同步,可能产生多个实例
有些人认为使用 volatile 的原因是可见性,也就是可以保证线程在本地不会存有 uniqueInstance 的副本,每次都是去主内存中读取。但其实是不对的。使用 volatile 的主要原因是其另一个特性:禁止指令重排序优化。
也就是说,在 volatile 变量的赋值操作后面会有一个内存屏障(生成的汇编代码上),读操作不会被重排序到内存屏障之前。比如上面的例子,取操作必须在执行完 1-2-3 之后或者 1-3-2 之后,不存在执行到 1-3 然后取到值的情况。从「先行发生原则」的角度理解的话,就是对于一个 volatile 变量的写操作都先行发生于后面对这个变量的读操作(这里的“后面”是时间上的先后顺序)。
' // 单例类
public class Singleton{ // 两次if,这样实例化只做一次,后面get时只return实例化对象。用volatile主要是因为new在JVM中做了3件事:1分配内存,2调用构造初始化成员变量形成实例(非null),3非将对象指向分配的内存空间(初始化完成)。JVM中有指令重排,顺序1-2-3或1-3-2.如果是后者,在3-2之间被另一线程抢占了,instance已经是非null,但是并没有初始化,另一线程会直接返回instance然后使用,这是不安全的。 private static volatile Singleton instance; private Singleton(){} public static Singleton getInstance(){ if(instance == null){ sychronized(Singleton.class){ if(instance == null){ instance = new Singleton(); } } } return instance; }}'
懒加载
线程安全
效率较高
' // 单例类
public class Singleton{ private Singleton(){} //私有,只有get方法能访问,读的时候不会同步 private static class SingletonIinstance{ private static final Singleton instance = new Singleton(); } public static Singleton getInstance() { return SingletonIinstance.instance; } }'
延时加载
效率高
线程安全
JDK1.5的枚举实现大力,避免同步问题,避免反序列化重现创建新的对象
' //枚举
public enumerate Singleton{ INSTANCE;} '
使用相应的获取对象的方法,不要使用new
频繁创建和销毁额对象
工具类对象
频繁访问数据库或文件的对象
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。