介绍:从字面上我们就能看出需要实现的功能—保证类只有一个实例,并提供一个访问此实例的方法。
优点:
1. 频繁使用的对象,可以减少创建对象所消耗的时间。
2. new操作次数的减少,对系统内存的使用频率也会减少,从而减轻GC压力,缩短GC停顿时间。
一、懒汉式
简述:懒汉式单例 在使用的时候去判断单例是否已经存在,然后再调用实例或创建实例 在懒汉式中需要考虑并发问题
1. 不使用同步方法
不使用同步方法,在不同情况下是可以实现单例的。但是在高并发的情况下可能会产生多个实例
public class SingletonLazyNoSync {
private static SingletonLazyNoSync uniqueInstance;
private SingletonLazyNoSync() {
}
// 静态工厂方法
public static SingletonLazyNoSync getInstance() {
// 下面是延迟实例化的方法
if (uniqueInstance == null)
uniqueInstance = new SingletonLazyNoSync();
return uniqueInstance;
}
}
2. 同步代码块
使用同步方法synchronized,能够在多线程中很好的工作,遗憾的是,效率很低
public class SingletonLazySync {
private static SingletonLazySync uniqueInstance;
private SingletonLazySync() {}
public static synchronized SingletonLazySync getInstance() {
// synchronized防止在多线程的情况下创建时会产生多个对象(但是synchronized会降低性能,同步一个方法能使程序效率下降100倍)
// 下面是延迟实例化的方法
if (uniqueInstance == null)
uniqueInstance = new SingletonLazySync();
return uniqueInstance;
}
}
3. 双重检验加锁
使用双重检验加锁,在getInstance方法中减少同步
public class SingletonVolatile {
// volatile保证在多线程的时候,每个线程能正确的处理这个单例
private volatile static SingletonVolatile uniqueInstance;
private SingletonVolatile() {}
public static SingletonVolatile getInstance() {
if (uniqueInstance == null)
synchronized (SingletonVolatile.class) {
if (uniqueInstance == null)
uniqueInstance = new SingletonVolatile();
}
return uniqueInstance;
}
}
二、饿汉式
简述:饿汉就是类一旦加载,就把单例初始化完成,保证getInstance的时候,单例是已经存在的了
1.静态变量
饿汉式提前实例化,但只要我们初始化类SingletonStatic,不管我们是不是调用getInstance()都会存在一个实例在内存中
public class SingletonStatic {
private SingletonStatic() {}
private static final SingletonStatic single = new SingletonStatic();
public static SingletonStatic getInstance() {
return single;
}
}
2.静态内部类
内部类式中,实现了延迟加载,当SingletonStaticClass被加载时,其内部类不会被初始化,即SingletonStaticClass被加载到JVM的时候,不会初始化单例类。只有我们调用了getInstance(),才会加载StaticClass创建唯一的实例INSTANCE到内存中.并且也解决了懒汉式中多线程的问题.
ps:这种方法也可能创建多个实例,比如,通过反射机制来加载单例类的私有构造函数。但是,这样的情况极少
public class SingletonStaticClass {
private static class StaticClass {
private static final SingletonStaticClass INSTANCE = new SingletonStaticClass();
}
private SingletonStaticClass() {}
public static SingletonStaticClass getInstance() {
return StaticClass.INSTANCE;
}
}
三、其它
public enum SingleInstance {
INSTANCE;
public void fun1() {
// do something
}
}
ps:最近在《Effective Java》看到的比较新奇的写法,看起来很简单,而且创建枚举是线程安全的,所以这写法也没有并发的问题。
更多模式: 一天一个设计模式—分类与六大原则