单例模式确保每个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
获取单例时,不能产生多个实例对象;
使用单例时,注意单例对象内的实例变量会被多线程共享,会有线程安全问题。
无状态对象,阻塞式创建
' // 单例类
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 删除。