定义
一个类只有一个实例,并提供一个访问它的全局访问点。
场景
1.我需要写一个文件管理的工具类,来存取本地的一个文件。
public class FileUtil {
public void saveInfo() {
System.out.println("save info success");
}
public void getInfo() {
System.out.println("get info success");
}
}
调用
FileUtil fileUtil = new FileUtil();
fileUtil.saveInfo();
2.程序中有大量的存取场景,每次调用都要创建fileUtil对象太麻烦了,我希望FileUtil能提供一个全局获取fileUtil的方法。
实现:在FileUtil新增一个静态方法,用于全局获取。
public class FileUtil {
public static FileUtil getInstance() {
return new FileUtil();
}
...
}
调用
FileUtil.getInstance().saveInfo();
3.虽然FileUitl提供了全局获取fileUtil对象的方法,但是每次都产生一个新的对象,而且用完就扔了,这样太浪费了。如果这里能只用一个对象就好了。
实现:在FileUtil中新增一个静态变量instance来存储FileUtil对象,需要时直接取instance。
public class FileUtil {
private static FileUtil instance;
public static FileUtil getInstance() {
if (instance == null) {
instance = new FileUtil();
}
return instance;
}
...
}
4.既然FileUtil已经提供了获取对象的方法,我不希望调用处还能通过new来创建它,否则依然会存在多个FileUtil的对象。
实现:将FileUitl的构造方法改为private
public class FileUtil {
private static FileUtil instance;
private FileUtil() {}
public static FileUtil getInstance() {
if (instance == null) {
instance = new FileUtil();
}
return instance;
}
...
}
至此,一个常见单例模式就完成了。
优化
上边完成的单例模式称为懒汉模式,它依然会存在缺陷。
1.懒汉模式(线程不安全),第一次调用的时候初始化,不会性能浪费,但第一次加载较慢,且只适用于单线程的环境。
public class Singleton {
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance() {
if (instance == null) {
// 多线程环境下,这里可能被创建多个对象,后边的覆盖前面
instance = new Singleton();
}
return instance;
}
}
2.懒汉模式(线程安全),能在多线程中很好的工作,但效率不高。
public class Singleton {
private static Singleton instance;
private Singleton(){}
// 这里保证线程安全,但是会在每次调用都试图加锁,即使instance已经存在,效率不高。
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
3.双重检查模式(DCL),解决了线程安全和性能的问题,资源利用率较高。
public class Singleton {
private Singleton() {}
private static Singleton instance;
public static Singleton getInstance() {
// 当instance已经存在的时候就不需要加锁了。
if(instance == null) {
synchronized(Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
4.饿汉模式,方法变量全部静态,类加载时直接初始化。但是过早的创建实例,会降低内存的使用效率。
而且如果始终没用到该类,就会造成性能浪费。
public class Singleton {
private static Singleton instance = new Singleton();
private Singletion(){}
public static Singleton getInstance() {
return instance;
}
}
5.内部类单例模式,首次创建的时候会初始化,解决了4中过早创建实例的问题
public class Singleton {
private Singleton(){}
public static Singleton getInstance() {
reture SingletonHolder.instance;
}
private static class SingletonHolder {
private static final Singleton instance = new Singleton();
}
}
Kotlin实现
1.如果单例类能够自己定义,直接使用object代替class即可
object Singleton {
}
2.单例类不能自定义,如Gson
object GsonUitl {
val gson = Gson()
}
优点
1.类可以自己控制实例化的过程
2.系统中只存在一个对象,可以节约资源
3.避免对共享资源多处占用
缺点
1.不适用于多变复杂的情况
2.没有抽象层,不方便扩展
3.多线程模式下容易引起数据错误
4.长时间不用的话,会被系统回收,执行状态丢失,下次使用会创建全新的对象