1、饿汉式
饿汉式就是类加载后就创建好了单例,直接拿就行,但该方法容易产生垃圾
public class Singleton1 {
//构造器私有化 防止外部实例
private Singleton1() {
}
private static final Singleton1 SINGLETON_1 = new Singleton1();
public static Singleton1 getInstance(){
return SINGLETON_1;
}
}
2、懒汉式,线程不安全
懒汉式就是,只有我使用的时候才去创建对象,但多线程条件下可能会破坏单例
public class Singleton2 {
//构造器私有化 防止外部实例
private Singleton2(){
}
private static Singleton2 SINGLETON_2;
public static Singleton2 getInstance(){
if (SINGLETON_2 == null){
SINGLETON_2 = new Singleton2();
}
return SINGLETON_2;
}
}
3、线程安全的懒汉式
使用volatile防止了指令重排,不加可能会产生半初始化对象(加载了但没有执行构造函数)
使用synchronized时对象为null时使线程同步防止创建多个对象
public class Singleton3 {
private Singleton3(){
}
private static volatile Singleton3 SINGLETON_3;
public static Singleton3 getInstance(){
if (SINGLETON_3 == null){
synchronized(Singleton3.class){
SINGLETON_3 = new Singleton3();
}
}
return SINGLETON_3;
}
}
4、使用静态内部类实现懒汉式单例
使用静态内部类去创建单例,因为静态内部类只会实例化一次,所以第一次实例化以后,每次拿到的都是同一个对象,都是那个静态常量
public class Singleton5 {
private Singleton5(){
}
private static Singleton5 singleton5;
public static Singleton5 getInstance(){
return SingletonHander.singleton;
}
private static class SingletonHander{
private static final Singleton5 singleton = new Singleton5();
}
}
5、使用枚举实现懒汉式单例
《Effective Java》
这种方法在功能上与公有域方法相近,但是它更加简洁,无偿提供了序列化机制,绝对防止多次实例化,即使是在面对复杂序列化或者反射攻击的时候。虽然这种方法还没有广泛采用,但是单元素的枚举类型已经成为实现 Singleton的最佳方法。—-《Effective Java 中文版 第二版》
public class Singleton4 implements Serializable {
@Serial
private static final long serialVersionUID = -2675976638179016828L;
//构造器私有化
private Singleton4(){
}
private static Singleton4 SINGLETON4;
//调用该方法就会执行.singleton4;执行这个方法就会
//加载内部枚举,加载内部枚举类然后会创建一个枚举项,一个枚举项就是一个枚举的实例
//所以在创建一个枚举项时会调用内部枚举的构造方法,从而创建一个单例
public static Singleton4 getInstance(){
return SingletonHander.instance.singleton4;
}
private enum SingletonHander{
instance;//枚举项,每个枚举项只会创建一个
private final Singleton4 singleton4;
SingletonHander() {
singleton4 = new Singleton4();
}
}
}