单例模式
单例模式应该是程序员最常遇到的设计模式
单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。
一饿汉式 (两种)
顾名思义 系统饿了 上来就吃
也即JVM在加载这个类时就完成了单例的创建,JVM也保证了它时线程安全的 效率也高
不足:在类加载时就完成实例化,没有懒加载的效果,如果从始至终没有使用过这个实例会造成内存浪费
public class Singleton {
public static final Singleton instance = new Singleton();
private Singleton(){
}
}
public class Singleton {
public static Singleton instance ;
static {
instance = new Singleton();
}
private Singleton(){
}
}
二懒汉式 (四种)
顾名思义 太懒了 你用到我的时候我再实例化
1.懒加载模式 效率高
2.线程不安全 一个JVM种可能存在多个实例
public class Singleton {
private static Singleton instance =null;
public static Singleton getInstance(){
if (instance == null){
instance = new Singleton();
}
return instance;
}
private Singleton(){
}
}
1.这种方法与上面唯一的不同是加了synchronized 同步锁
2.懒加载模式 锁粒度大 效率低
3.线程安全
public class Singleton {
private static Singleton instance =null;
public synchronized static Singleton getInstance(){
if (instance == null){
instance = new Singleton();
}
return instance;
}
private Singleton(){
}
}
1.懒加载模式 效率较高
2.线程不安全
public class Singleton {
private static Singleton instance =null;
public static Singleton getInstance(){
if (instance == null){
synchronized(Singleton.class){
instance = new Singleton();
}
}
return instance;
}
private Singleton(){
}
}
1.懒加载模式 效率高
2.极端情况下线程不安全
public class Singleton {
private static Singleton instance =null;
public static Singleton getInstance(){
if (instance == null){
synchronized(Singleton.class){
if (instance == null){
instance = new Singleton();//这一步可能导致线程不安全
原因 是因为无法保证有序性
我们正常理解的new 一个对象 分为三步
1.JVM堆内存种开辟一块空间
2.填充对象属性的值
3.将instance 指针指向该区域
但是在多线程环境中CUP会对指令重排序 执行顺序可能变为 132
这种情况下当此线程执行完13两步操作 该实例对象已经不为null,别的线程就可能拿到没有初始化过的实例,惊醒操作 可以用volatile 保证此有序性
}
}
}
return instance;
}
private Singleton(){
}
}
双重检查 懒加载 线程安全 高效
完美? 不不不 以上这几种 还都能用反射和序列化创建多个对象
public class Singleton {
private volatile static Singleton instance =null;
public static Singleton getInstance(){
if (instance == null){
synchronized(Singleton.class){
if (instance == null){
instance = new Singleton();
}
}
}
return instance;
}
private Singleton(){
}
}
三静态内部类
静态内部类 懒加载 高效 线程安全 但是 还是可以用反射和序列化获取
public class Singleton {
private static class SingletonInstance{
private static Singleton instance = new Singleton();
}
public static Singleton getInstance(){
return SingletonInstance.instance;
}
private Singleton(){
}
}
四枚举
枚举实现 推荐使用 安全 高效 JVM保证反射和序列化也无法创建多个实例
public enum Singleton {
instance;
}