码迷,mamicode.com
首页 > 其他好文 > 详细

设计模式之单例模式

时间:2020-06-05 23:00:22      阅读:63      评论:0      收藏:0      [点我收藏+]

标签:直接   私有化   避免   com   actor   静态   工具类   实现   共享变量   

设计模式之单例模式

1. 概念

? 所谓单例模式,就是采取一定的方法使得系统中只存在某个类的一个实例,并且该类只提供一个获取对象实例的方法(静态方法);比如Hibernate的SessionFactory

2.实现

1.静态常量/静态代码块方法(饿汉式)

类加载的时候就完成了实例化,不存在线程同步问题,但是如果至始至终这个对象都用不到,那就变成了内存的浪费,没有达到Lazy Loading的效果

步骤:

  • 构造器私有化(外部无法通过new来创建对象)

  • 类的内部创建对象

  • 向外暴露一个公共的getInstance方法

    class Singleton{
    	//1.私有化构造器
        private Singleton(){}
        
        //2.类内部创建对象
        private final static Singleton instance = new Singleton();
        //或者将创建对象放在静态代码块中
        private static Singleton instance ;
        static{
            instance = new Singleton();
        }
        
        //3. 提供一个公共的方法获取对象
        public static Singleton getInstance(){
            return instance;
        }
        
        
    }
    

2. 懒汉式(Lazy Loading的效果)

1. 线程不安全

class Singleton{
	//1.私有化构造器
    private Singleton(){}
    //2.类内部定义对象
    private  static Singleton instance;   
    //3. 提供一个公共的方法获取对象
    public static Singleton getInstance(){
        if(instance == null){//需要时再创建,不会在类加载的时候创建
            instance = new Singleton();
        }
        return instance;
    }
}

该方法只能在单线程下执行,多线程下有可能多个线程同时进入到 if 模块,以至于创建出多个实例,实际开发中不能使用这种方法

2.线程安全,同步方法

getInstance()方法中加上同步代码关键字synchronized来解决线程问题

    public static synchronized Singleton getInstance(){
        if(instance == null){//需要时再创建,不会在类加载的时候创建
            instance = new Singleton();
        }
        return instance;
    }

效率过低,我们在创建对象实例的时候才需要同步,而这样的代码我们在之后的每次获取实例都会进行一次同步,方法进行同步的效率太低了

3.双重检查

volatile可以使共享变量一旦修改就刷新到内存里去,在getInstance方法中,通过synchronized同步来使得线程安全,当多个线程进入外层 if 时,会受到synchronized关键字作用,单个进入到内层 if 中,当instance被创建后,由于volatile的作用会立刻刷新到内存,等待的线程就会在内层 if 中判断false,即保证了单个实例创建,再后来的线程在外层 if 就false了,也解决了效率问题

class Singleton{
	//1.私有化构造器
    private Singleton(){}
    //2.类内部定义对象
    private  static volatile Singleton instance;  // volatile可以使共享变量一旦修改就刷新到内存里去
    //3. 提供一个公共的方法获取对象
    public static Singleton getInstance(){
        if(instance == null){//需要时再创建,不会在类加载的时候创建
            synchronized(Singleton.class){
                if(instance==null){
           			 instance = new Singleton();                    
                }
            }
        }
        return instance;
    }   
}

开发中可以使用

4.静态内部类

JVM在类加载的时候是线程安全的,并且类加载的时候,其静态内部类不会被加载,所以我们可以利用这一点来达到线程安全和Lazy Loading的效果

class Singleton{
    //1.对象实例在内部类加载时被创建
    public static class SingletonInstance{
        private static final Singleton INSTANCE = new Singleton();
    }
    
	//2.私有化构造器
    private Singleton(){} 
    //3. 提供一个公共的方法获取对象,调用该方法时,内部类第一次被加载,创建对象实例
    public static Singleton getInstance(){
        return SingletonInstance.INSTANCE;
    }   
}

开发中推荐使用

5.枚举

借助JDK1.5中添加的枚举来实现单例模式。不仅可以避免多线程同步问题,而且还能防止反序列化重新创建性的对象

enum Singleton{
	INSTANCE;
    public void play(){
        //code。。。
    }
}

//可以直接调用获取
Singleton instance = Singleton.INSTANCE;
//枚举中的方法也可以直接调用
instance.play();

开发中推荐使用

3.应用场景

  • 需要经常创建、销毁的对象
  • 创建对象耗时过多或损耗资源过多的,但又经常用到的重量级对象
  • 工具类对象、频繁访问数据库或文件的对象(比如数据源、session工厂等等)

分析Runtime源码中使用的单例模式

技术图片

设计模式之单例模式

标签:直接   私有化   避免   com   actor   静态   工具类   实现   共享变量   

原文地址:https://www.cnblogs.com/JIATCODE/p/13052496.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!