饿汉式单例
在静态成员变量中直接初始化,发生在JVM的类加载中,不会出现线程安全问题,缺点是直接使用类初始化会占用堆内存。
/**
* 实现一个饿汉式的单例
*/
public final class HungrySingleton implements Serializable {
static private HungrySingleton INSTANCE = new HungrySingleton();
static public HungrySingleton getINSTANCE(){
return INSTANCE;
}
static public Object getObject(){
return INSTANCE;
}
}
懒汉式单例
改进饿汉直接初始化的模式,调用的时候初始化,由于不保证线程安全,所以加了synchronized锁,缺点是其实只要保证第一次初始化的时候没有多线程问题就行,后面拿单例对象不需要锁的保护,synchronized是比较重量级的操作,会带来一定的性能影响。
/**
* 饿汉式的单例
*/
public final class LazySingleton {
static private LazySingleton INSTANCE = null;
// 这里加synchronized确实可以保证单例线程安全了,但是其实synchronized操作太重了,而且我们只要保证第一次INSTANCE对象创建出来就可以了
static public synchronized LazySingleton getInstance(){
if(INSTANCE == null){
INSTANCE = new LazySingleton();
}
return INSTANCE;
}
}
双锁检测单例模式(DCL)
双锁的作用就是通过两个if判断是否是第一次初始化,如果是第一次则加锁->初始化->返回,如果初始化过了直接返回,为了保证第一个if包裹的代码块不会发生指令重排序,造成多个单例对象,所以还要用volatile保证单例对象的可见性以及防止指令重排序。
/**
* Double check Lock
* 双锁检查单例实现
*/
public class DCLSingleton {
private static volatile DCLSingleton INSTANCE = null; // volatile保证临界区以外的代码禁止指令重排序,防止其他没加锁的线程访问时,正好,临界区指令重排了,INSTANCE实例先构造出来,但是还没有赋值
public DCLSingleton() {
}
public static DCLSingleton getInstance(){
if(INSTANCE == null){
synchronized (DCLSingleton.class){ // synchronized保证第一次创建时临界区的原子性、可见性、有序性
if(INSTANCE == null){
INSTANCE = new DCLSingleton();
}
}
}
return INSTANCE;
}
}
枚举实现单例
普通实现
public enum EnumSingleton {
INSTANCE;
public Object getInstance(){
return INSTANCE;
}
}
类内实现
package lesson08_singleton;
/**
* 类中通过枚举实现单例
* 原理上枚举类也是静态类,类加载时执行构造,由JVM内部保证其线程安全,同时防止反序列化以及发射,
* 是比较推荐的单例方法
*/
public class EnumSingleton2 {
private EnumSingleton2(){
}
public static enum SingletonEnum{
INSTANCE;
private EnumSingleton2 instance = null;
private SingletonEnum(){
instance = new EnumSingleton2();
}
public EnumSingleton2 getInstance(){
return instance;
}
}
}
静态类实现
JVM类加载阶段实现初始化,调用时返回。
public class StaticSingleton {
private static class InnerClass {
public static StaticSingleton INSTANCE = new StaticSingleton();
}
public static StaticSingleton getInstance(){
return InnerClass.INSTANCE;
}
}