SingletonTest(studio plugin)
![](https://img.haomeiwen.com/i1986163/37f091ecec6dc2ab.png)
单例模式的几种基本写法
饿汉式:拿空间换时间
不管需不需要我先加载了再说,先在内存中开辟一块空间,占用一块地方,等用到了直接就拿来用.
饿汉式缺点:不需要的时候就加载了,造成资源浪费。
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton(){
}
public static Singleton getInstance(){
return INSTANCE;
}
}
懒汉式:拿时间换空间
只有我需要他的时候才去加载它
懒汉式缺点:效率低,第一次加载需要实例化,反应稍慢。每次调用 getInstance 方法都会进行同步,消耗不必要的资源。
public class Singleton {
private static Singleton instance;
private Singleton(){
}
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
双重检查单例( DCL 实现单例):
优点:资源利用率高,第一次执行方法是单例对象才会被实例化;
缺点:第一次加载时会稍慢,jdk1.5之之前有可能会加载会失败;
public class Singleton {
private static Singleton instance;
private Singleton(){
}
public static Singleton getInstance(){
if(instance == null){
synchronized (Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
这种写法估计是我们在开发中最常用的,这次代码的亮点是是在 getInstance() 方法中进行了双重的判断,第一层判断的主要避免了不必要的同步,第二层判断是为了在 null 的情况下再去创建实例;举个简单的列子:假如现在有多个线程同时触发这个方法: 线程 A 执行到 instance = new Singleton() ,它大致的做了三件事:
-
给 Singleton 实例分配内存,将函数压栈,并且申明变量类型;
-
初始化构造函数以及里面的字段,在堆内存开辟空间;
-
将 instance 对象指向分配的内存空间;
step.png
静态内部内实现单例:
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static class SingletonInstance {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
这种方式不仅确保了线程的安全性,也能够保证对象的唯一性,同时也是延迟加载,很多技术大牛也是这样推荐书写。
枚举实现单例:
public enum SingletonEnum {
INSTANCE;
public void doSomething() {
}
}
优点:相对于其他单例来说枚举写法最简单,并且任何情况下都是单列的,JDK1.5之后才有的。
使用容器单例:
public class SingletonManager {
private static Map<String, Object> objMap = new HashMap<>();
private SingletonManager() {
}
public static void putObject(String key, String instance){
if(!objMap.containsKey(key)){
objMap.put(key, instance);
}
}
public static Object getObject(String key){
return objMap.get(key);
}
}
在程序开始的时候将单例类型注入到一个容器之中,也就是单例 ManagerClass ,在使用的时候再根据 key 值获取对应的实例,这种方式可以使我们很方便的管理很多单例对象,也对用户隐藏了具体实现类,降低了耦合度;但是为了避免造成内存泄漏,所以我们一般在生命周期销毁的时候也要去销毁它。
网友评论