单例模式——懒汉式和饿汉式详解

单例模式——懒汉式和饿汉式详解,第1张

单例模式属于 创建型模式 的一种,应用于保证一个类仅有一个实例的场景下,并且提供了一个访问它的全局访问点,如spring中的全局访问点BeanFactory,spring下所有的bean都是单例。

单例模式的特点:从系统启动到终止,整个过程只会产生一个实例。

单例模式常用写法:懒汉式,饿汉式,注册式,序列化式。

下面比较一下懒汉式和饿汉式:

懒汉式 :默认不会实例化,什么时候用什么时候new。

public class Lazy{

        private Lazy(){}

        //默认不会实例化,什么时候用什么时候new

        private static Lazy lazy = null

        public static synchronized Lazy getInstance(){

            if(lazy==null){

                lazy = new Lazy()

            }

            return lazy

        }

}

饿汉式 :类加载的时候就 实例化 ,并且创建单例对象。

public class Hungry{

        private Hungry(){}

        // 类加载的时候就实例化,并且创建单例对象

        private static final Hungry hungry = new Hungry()

        public static Hungry getInstance(){

                return hungry

        }

}

懒汉式默认不会 实例化 ,外部什么时候调用什么时候new。

饿汉式在类加载的时候就实例化,并且创建单例对象。

饿汉式:线程安全。

在线程还没出现之前 就已经实例化了,因此饿汉式线程一定是安全的。

懒汉式:线程不安全。 

因为懒汉式加载是在使用时 才会去new 实例的,

那么你去new的时候是一个动态的过程,是放到方法中实现的。

比如:

public static synchronized Lazy getInstance(){  

         if(lazy==null){  

                lazy=new Lazy() 

        } 

}

如果这个时候有多个线程访问这个实例 (这个时候实例还不存在,还在new),

就会进入到方法中,有多少线程就会new出多少个实例。

一个方法return一个实例,那最终return出哪个呢?

是不是会覆盖很多new的实例?

这种情况当然也可以解决,那就是 加同步锁 ,避免这种情况发生 。

饿汉式没有加任何的锁,因此执行效率比较高。

懒汉式一般使用都会加同步锁,效率比饿汉式差。

饿汉式在类加载的时候就初始化,不管你是否使用,它都实例化了,

所以会占据空间,浪费内存。

懒汉式什么时候需要什么时候实例化,相对来说不浪费内存。

单件模式用途:

单件模式属于工厂模式的特例,只是它不需要输入参数并且始终返回同一对象的引用。

单件模式能够保证某一类型对象在系统中的唯一性,即某类在系统中只有一个实例。它的用途十分广泛,打个比方,我们开发了一个简单的留言板,用户的每一次留言都要将留言信息写入到数据库中,最直观的方法是没次写入都建立一个数据库的链接。这是个简单的方法,在不考虑并发的时候这也是个不错的选择。但实际上,一个网站是并发的,并且有可能是存在大量并发 *** 作的。如果我们对每次写入都创建一个数据库连接,那么很容易的系统会出现瓶颈,系统的精力将会很多的放在维护链接上而非直接查询 *** 作上。这显然是不可取的。

如果我们能够保证系统中自始至终只有唯一一个数据库连接对象,显然我们会节省很多内存开销和cpu利用率。这就是单件模式的用途。当然单件模式不仅仅只用于这样的情况。在《设计模式:可复用面向对象软件的基础》一书中对单件模式的适用性有如下描述:

1、当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。

2、当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。

下面对单件模式的懒汉式与饿汉式进行简单介绍:

1、饿汉式:在程序启动或单件模式类被加载的时候,单件模式实例就已经被创建。

2、懒汉式:当程序第一次访问单件模式实例时才进行创建。

如何选择:如果单件模式实例在系统中经常会被用到,饿汉式是一个不错的选择。

懒汉式

public class LazySingle {

private LazySingle() {}

private static LazySinglesingle =null

    public static synchronized  LazySinglegetInstance() {

if (single ==null) {

single =new LazySingle()

        }

return single

    }

}

饿汉式

public class ESingle {

private ESingle(){}

private static final ESingleeSingle =new ESingle()

    public static ESinglegetInstance(){

return eSingle

    }

}

懒汉式和饿汉式区别:

实例化方面:懒汉式默认不会实例化,外部什么时候调用什么时候new。饿汉式在类加载的时候就实例化,并且创建单例对象。

线程安全方面:饿汉式线程安全 (在线程还没出现之前就已经实例化了,因此饿汉式线程一定是安全的)。懒汉式线程不安全( 因为懒汉式加载是在使用时才会去new 实例的,那么你去new的时候是一个动态的过程,是放到方法中实现的,比如:public static synchronized Lazy getInstance(){   if(lazy==null){  lazy=new Lazy()} 如果这个时候有多个线程访问这个实例,这个时候实例还不存在,还在new,就会进入到方法中,有多少线程就会new出多少个实例。一个方法只能return一个实例,那最终return出哪个呢?是不是会覆盖很多new的实例?这种情况当然也可以解决,那就是加同步锁,避免这种情况发生) 。

执行效率上:饿汉式没有加任何的锁,因此执行效率比较高。懒汉式一般使用都会加同步锁,效率比饿汉式差。

性能上:饿汉式在类加载的时候就初始化,不管你是否使用,它都实例化了,所以会占据空间,浪费内存。懒汉式什么时候需要什么时候实例化,相对来说不浪费内存。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/bake/8010836.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-12
下一篇 2023-04-12

发表评论

登录后才能评论

评论列表(0条)

保存