1.饿汉模式
package share.singleton;
/**
* 饱汉模式
* 线程安全 类初始化时实例化单例对象 有些场景下不适用 如一些参数在运行时才能就绪
*/
public class Singleton1 {
private static Singleton1 singleton = new Singleton1();
public static Singleton1 getInstance() {
return singleton;
}
}
2.懒汉模式
package share.singleton;
/**
* 饥汉模式
* 在获取实例时初始化单例对象
*/
public class Singleton2 {
private static Singleton2 singleton2;
/**
* caution !!
*/
private Singleton2() {
}
public static Singleton2 getInstance() {
//并发时多个线程会初始化多次 造成系统中存在超过一个单例对象
// 虽会被系统回收 但在一些场景下会造成系统错误 如并发线程读取配置不一致
if (null == singleton2) {
singleton2 = new Singleton2();
}
return singleton2;
}
}
3.获取单例方法加锁
package share.singleton;
/**
* synchronized
* 获取单例加锁 线程安全 但并发率差
*/
public class Singleton3 {
private static Singleton3 singleton3;
private Singleton3() {
}
/**
* 这里锁对象是?
*/
public static synchronized Singleton3 getInstance() {
if (null == singleton3) {
singleton3 = new Singleton3();
}
return singleton3;
}
}
4.只在初始化阶段加锁
package share.singleton;
/**
* synchronized
* 获取单例加锁 线程安全 但并发率差
*/
public class Singleton3 {
private static Singleton3 singleton3;
private Singleton3() {
}
/**
* 这里锁对象是?
*/
public static synchronized Singleton3 getInstance() {
if (null == singleton3) {
singleton3 = new Singleton3();
}
return singleton3;
}
}
5.单例引用多线程可见
package share.singleton;
/**
* 单例引用增加volatile
*/
public class Singleton5 {
private volatile static Singleton5 singleton5;
private Singleton5() {
}
public static Singleton5 getInstance() {
if (null == singleton5) {
//volatile可以保证单例对象被初始化后对其他线程可见,但有可能其他线程已经进入初始化区域
synchronized (Singleton4.class) {
singleton5 = new Singleton5();
}
}
return singleton5;
}
}
6.二次判断是否单例是否已被初始化
package share.singleton;
public class Singleton6 {
private volatile static Singleton6 singleton6;
private Singleton6() {
}
public static Singleton6 getInstance() {
if (null == singleton6) {
//volatile可以保证单例对象被初始化后对其他线程可见,但有可能其他线程已经进入初始化区域
synchronized (Singleton4.class) {
//该区域只会有一个线程访问
if (null == singleton6) {
singleton6 = new Singleton6();
}
}
}
return singleton6;
}
}
7.静态内部类
package share.singleton;
/**
* 静态内部类
* 优点 类加载器保证线程安全
* 缺点 无法传参
*/
public class Singleton7 {
private static Singleton7 singleton7;
private Singleton7() {
}
public static Singleton7 getInstance() {
return Holder.SINGLETON7;
}
private static class Holder {
private static Singleton7 SINGLETON7 = new Singleton7();
}
}
8.枚举
package share.singleton;
/**
* 枚举
* 类的初始化线程安全
*/
public enum Singleton8 {
/**
* 单例
*/
INSTANCE;
public static Singleton8 getInstance() {
return INSTANCE;
}
}
9.思考
单例能否保证系统中真的有且只有一个实例对象?能否避免反射对单例的破坏