Java单例模式常见写法比较

一. 单例模式

1.实现单例模式的几个关键点

a)     构造函数不对外开发,一般是Private

b)     通过静态方法或者枚举返回单例类对象

c)     确保单例类的对象有且只有一个,尤其在多线程环境下

d)     确单例在反序列化时不会被重新构建对象

2.  单例模式的几种实现

1.懒汉式单例模式

//懒汉式单例类.在第一次调用的时候实例化自己  

publicclass Singleton { 

    private Singleton() {} 

    private static Singleton single=null; 

    //静态工厂方法  

    public static Singleton getInstance(){ 

         if (single == null) {   

             single = new Singleton(); 

         }   

        return single; 

    } 

}

风险:多线程下回出现多个实例,不建议使用。

 

三种方法解决问题:

1、在getInstance方法上加同步:效率低,带来不必要的同步开销

publicstatic synchronized Singleton getInstance() { 

         if (single == null) {   

             single = new Singleton(); 

         }   

        return single; 

}

2.双重检查锁定:效率高

public static Singleton getInstance() { 

        if (singleton == null){   

            synchronized(Singleton.class) {   

               if (singleton== null) {   

                  singleton =new Singleton();  

               }   

            }   

        }   

        return singleton;  

    }

说明:第一重判断是为了避免不必要的同步,第二重判断则是为了保证是单个实例对象。

优点:资源利用率高,只有第一次调用的时候才会生成实例,使用比较广泛。

缺点:第一次加载比较慢,另外还有些jdk版本问题。不过普通情况不用关注。

3.静态内部类:推荐

public class Singleton {   

   private static class LazyHolder {   

       private static final Singleton INSTANCE= new Singleton();   

   }   

   private Singleton (){}   

   public static final Singleton getInstance() {   

       return LazyHolder.INSTANCE;   

   }   

这种比上面1、2都好一些,是《Java并发编程实践》推荐的方法。既实现了线程安全,又避免了同步带来的性能影响。解释下,当第一次加载Singleton的时候并不会直接去初始化LazyHolder类,只有在我们调用getInstance方法的时候才会去调用到该类,这时候回去初始化对象。

优点:保证线程安全,保证了单例的唯一性,又能起到延时加载的作用。

2.饿汉式单例模式

public class Singleton {  

    private Singleton() {}  

    private static final Singleton1 single = new Singleton1();  

    //静态工厂方法   

    public static Singleton getInstance() {  

        return single;  

    }  

说明:饿汉式单例类.在类初始化时,已经自行实例化 ,会消耗一些资源,但是安全有效,天生线程安全。

 

3.枚举单例

public enum Singleton { 

 

    INSTANCE; 

 

    public void doSomething(){

      //TODO

    }

 }

说明:这个是“java高效编程指南”《Effective Java》推荐的方法。

优点:简单,线程安全,任何时候都是一个实例对象。感兴趣的可以反编译看源码就知道了。另外最大的优点是可以避免被反序列化重新生成对象,我们在反序列化上面的单例模式的类的时候,即使它的构造方法是私有的,依然可以通过特殊途径去拿到它的对象,不过反序列化操作提供了一个钩子方法给我们,readResolve(),用这个可以控制在反序列化的时候还是原来那个对象,而不是重新生成。在单例中加入下面这个方法即可防止被反序列化生成多个对象(这个是复杂需求下的处理办法,实际我们很少碰到的,可以不必关于关心)。

private  Object readResolve() throwsObjectStramException{

      return instance;//返回我们自己的单例对象

}

 

另外:容器实现单例

这个就不多说了,用的更少,但是在源代码中我们会看到,它实际就是使用一个Map集合将所有的单例对象给储存起来Key-Values键值对形式保存起来,然后我们要拿某一个单例对象的时候就通过某个key来取。

 

3.  总结

在没有高并发的时候,其实上面的单例模式大多都是可以的,不过比较推荐使用--双重检查锁定和静态内部单例来做。

单例模式的优缺点

优点:

1.    只有一个实例对象,减少了内存开销,特别在对象频繁创建和销毁的时候,这个过程无法进行优化,单例模式就体现出优势了

2.    单例对象只有一个,那么当某个对象需要较多系统资源的时候就可以减少系统开销,让它永驻内存,谁用就拿去,没必要创建多个

3.    避免对资源的多重占用,比如读写某个文件,单例模式保证了安全性,不会发生同时读写问题

4.    可以设置全局的访问点,优化和共享资源的访问。比如可以设计一个类,它来负责全局的数据映射。

缺点:

1.    单例模式一般没有接口,扩展性很差,正常的只要你想扩展,就必须修改源代码

2.    单例对象如果持有Context,非常容易造成内存泄漏问题,因此要十分注意,最好给单例对象的Context是Application Context.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值