您现在的位置是:首页 >其他 >设计模式-单例模式网站首页其他
设计模式-单例模式
单例模式
一提到单例模式必须要要先想到构造方法私有化,然后通过一个方法来获取这个对象的实例,且在一个进程中只会存在一份这个对象的实例。
在开发过程中其实有些对象我们是经常用到的,并且这个对象还不轻量,那我们就可以考虑使用单例模式,这个对象在内存中只会创建一次,后面使用的时候直接获取这个对象的实例,拿来使用就好了。
使用场景
需要频繁创建和销毁的对象、创建对象耗时过多或耗费资源过多(重量级对象),但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象。
单例模式的实现方法
1、饿汉式(静态常量)
class Singleton {
// 1.构造方法私有化
private Singleton() {}
// 2.创建一个变量来保存实例对象
private final static Singleton instance = new Singleton();
// 3.通过一个公共的方法来获取这个对象
public static Singleton getInstance() {
return instance;
}
}
优缺点:
1、写法简单,在类装载的时候就完成初始化。避免了线程同步问题。
2、容易造成内存浪费。
结论:
这种方法可用,但是可能造成内存浪费。
2、饿汉式(静态代码块)
class Singleton {
private static Singleton instance;
private Singleton() {}
// 这里通过静态代码块创建对象
static {
instance = new Singleton();
}
public static Singleton getInstance() {
return instance;
}
}
优缺点:
1、同上面一样,简单,避免了线程问题,但是会造成内存浪费。
结论:
可用,会造成内存浪费
3、懒汉式(线程不安全)
class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
优缺点:
1、起到了懒加载的效果,但是只能在单线程下面使用
2、在多线程下如果多个线程同事进入到了if (instance == null)
判断语句块中,那么他们都会创建一个实例,这样返回的实例就不是同一个了。
结论:
在多线程环境下不能使用。
4、懒汉式(线程安全,同步方法)
class Singleton {
private static Singleton instance;
private Singleton() {}
// 在getInstance方法上增加synchronized,同时只能有一个线程执行该方法
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
优缺点:
1、解决了线程不安全的问题
2、效率太低,每一个线程执行都要通过锁,如果同一时刻线程很多,都会阻塞在这个方法这里。
结论:
可以使用,但是不推荐使用
5、懒汉式(线程安全,同步代码块)
class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
// 如果同时多个线程进入到这个判断语句块中
// 那么只是在这个同步代码快这里阻塞一下,后面也是都会执行这个创建实例的
// 线程不安全
synchronized (Singleton.class) {
instance = new Singleton();
}
}
return instance;
}
}
优缺点:
1、线程不安全。如果同时多个线程进入到判断语句块中,线程只是在这个同步代码快这里阻塞一下,后面也是都会执行这个创建实例的
结论:
线程不安全,不能使用这种方式
6、双重检查
class Singleton {
// 这里的volatile很关键
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
优缺点:
1、双重检查机制可以保证线程安全,我们在代码中进行了两次判断,在同步代码块中的代码同一时间只会有一个线程执行,下一个线程进来再判断一次就一定不会创建多个实例。
2、线程安全;延迟加载;效率高
结论:
可以使用,在实际开发中推荐使用这种方式
7、静态内部类
class Singleton {
private Singleton() {}
private static class SingletonInstance {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
优缺点:
1、采用了类加载的机制来保证初始化实例的时候只有一个线程。
2、静态内部类在状态的时候并不会立即实例化,而是在需要的时候才会状态SingletonInstance内部类,从而完成Singleton的实例化
3、类的静态属性只会在第一次加载类的时候初始化,所以这里是JVM帮我们保证了线程安全,在类初始化的时候,别的线程是无法进入的。
结论:
线程安全,效率高,延迟加载。推荐使用
8、枚举
enum Singleton {
INSTANCE;
public void method() {
System.out.println("枚举只会创建一个对象,都可以执行这个方法");
}
}
优缺点:
1、借助枚举来实现单例模式,不仅能避免多线程问题,还能防止反序列化重新创建新对象。
2、是Effective Java作责Josh Bloch提倡的方式
结论:
推荐使用