单例模式与多线程总结(完整版)

单例模式的使用场景
  • 有频繁实例化然后销毁的情况,也就是频繁的new对象
  • 创建对象时耗时过多或耗资源过多,但又经常用到的对象
  • 频繁访问IO资源的对象,比如数据库连接池或访问本地文件
1.饿汉模式
public class Singleton{
    private static Singleton instance = new Singleton();
    private Singleton(){
        
    }
    public static Singleton getInstance(){
        return instance;
    }
}

2.不使用同步锁(懒汉模式)
public final class Singleton{
    private static Singleton instance  = null;
    private Singleton(){
        
    }
    public static Singleton getInstance(){
        if(instance == null)
           instance  = new Singleton();
           return instance;
    }
}
  • 该方法不安全 因此使用例子2 加个同步锁
3.使用同步方法
  • 锁整个方法
public class Singleton{
    private static Singleton instance;
    private Singleton(){
        
    }
    public static synchronized Singleton getInstance(){
        if(instance == null)
          instance = new Singleton();
          return instance;
    }
}

  • 同步的代价必然会一定程度的使程序的并发度降低
  • 因此需将同步的粒度降低
4.使用双重锁
  • 锁代码块
public class Singleton{
    private volatile static Singleton instance;
    private Singleton(){
        
    }
    
    public static Singleton getInstance(){
        if(instance == null){
            synchronized(Singleton.class){
                if(instance == null)
                    instance = new Singleton();
            }
        }
        return instance;
    }
}

  • **该方法的弊端是可能会得到没被完整初始化的对象! 得到一个没有初始化完全的对象并没有作用
  • 线程A在创建单例对象时,在构造方法被调用之前,就为该对象分配了内存空间并将对象的字段设置为默认值。此时线程A就可以将分配的内存地址赋值给instance字段了,然而该对象可能还没有初始化。线程B来调用newInstance()方法,得到是未初始化完全的单例对象,这就会导致系统出现异常行为。
  • 因此需要加上volatile 禁止指令重排,保证代码的有序性**
5.使用static代码块
public class Singleton{
    private static Singleton instance = null;
    private Singleton(){
        
    }
    static{
        instance = new Singleton();
    }
    public static Singleton getInstance(){
        return instance;
    }
}

6.静态内部类
  • 使用jvm的机制进行同步保证,没有一个同步的关键字
public class Singleton{
    private static class Singleton{
        private  static final  Singleton instance = new Singleton();
    }
    public static Singeleton getInstance(){
        return Singleton.instance;
    }
}

  • 静态内部类如果遇到序列化对象,线程不安全
7.枚举方式(枚举类被暴露,违背职责单一原则)
public enum SingleEnum{
    INSTANCE;
    
    private Singleton instance;
    
    private SingleEnum(){
        instance = new Singleton();
    }
    public Singleton getInstance(){
        return instance;
    }
    
}
class Singleton{   //需要实现单例的类
    public Singleton(){
        
    }
}

  • 我们可以通过 SingleEnum.INSTANCE.getInstance() 来访问实例。而且创建枚举默认就是线程安全的,并且还能防止反序列化导致重新创建新的对象
8.枚举方式的完善
public class Factory{
    public enum SingleEnum{
        INSTANCE;
        
        private Singleton instance;
        
        private SingleEnum(){
            instance = new Singleton();
        }
        
        public static Singleton getInstance(){
            return instance;
        }
    }
    
    public static Singleton getInstance(){
        return SingleEnum.INSTANCE.getInstance();
    }
     
}

class Singleton{   //需要实现单例的类
    public Singleton(){
        
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值