简用单例模式

Posted 爱码就码

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了简用单例模式相关的知识,希望对你有一定的参考价值。

   前   言  

前面将各个设计模式合并起来简介了一下,现在认为还是该以单个的方式来贴一下,这样用起来更有方向。


  正   文  

单例方式

看到很多人写单例都不考虑线程安全,当多线程操作当时候,就可能出现多个实例,那么不就违背了单例的初衷了么?如果要维护到单例类中到成员,那就更尴尬了,我看到也实在是无奈,所以这里建议大家写单例是需要做到线程安全到!!

首先说推荐单例模式写法,其目的主要是为了做到线程安全:

1) DCL (Double CheckLock)

 
   
   
 
  1. public class Singleton {

  2.    private Singleton() {

  3.    }

  4.    /**

  5.     * instance = new Singleton();因为不是一个原子操作,所以在编译到时候大致有三件事

  6.     * 1:给Singleton实例分配内存

  7.     * 2:调用好Sinleton() 构造函数,初始化成员字段

  8.     * 3:将instance对象指向分配到内存空间(执行了这一步后instance将为null了)

  9.     * 但是:

  10.     * 在JDK1.5之前有JMM(java Memory Model内存模型)中Cache、寄存器到驻内存回写顺序到规定,会导致执行顺序到不确定性

  11.     * 可能123 ,也可能132。

  12.     * 再1.5之后 JDK调整了JMM,加入了volatile关键字

  13.     *

  14.     * 这里加入volatile 关键字主要是为了保证每次都从驻内存获取

  15.     */

  16.    private volatile static Singleton instance;

  17.    public static Singleton getInstance() {

  18.        if (instance == null) {

  19.            synchronized (Singleton.class) {

  20.                if (instance == null)

  21.                    instance = new Singleton();

  22.            }

  23.        }

  24.        return instance;

  25.    }

  26. }

DCL写法优点就是在第一次执行到时候才会实例化,效率高。缺点就是第一次加载反应稍慢,性能牺牲点。再JDK1.6以后使用,这种方式是不错的选择。

2) 静态内部类写法:

 
   
   
 
  1. private Singleton() {

  2.    }

  3.    private static class SingletonClassHolder {

  4.        private static final Singleton instance = new Singleton();

  5.    }

  6.    public static Singleton getInstance() {

  7.        return SingletonClassHolder.instance;

  8.    }

这是种单例方式,不光延迟了实例化,效率也高,也不需要双重检查锁定,并发上,性能就上去了。

3) 枚举

 
   
   
 
  1. public enum Singleton {

  2.    INSTANCE;

  3.    public void doS() {

  4.        Log.e("11", "11");

  5.    }

  6. }

枚举最大的优点就是简单。枚举在java种与普通类式一样的,用这种方式来做单例也式很好的,最重要的是在任何情况下,它都式线程安全的,任何情况下它都只有一个实例。

其他单例在反序列化的时候会因为readResolve方法,而重新生成对象

 
   
   
 
  1. //其他单例实现种,反序列化需要用这种方式来避免重新生成对象

  2. private Object readResolve() throws ObjectStreamException{

  3.    return instance;

  4. }

另外 :

  • 饿汉式:

 
   
   
 
  1. private static final Singleton instance = new Singleton();

  2.    private Singleton() {

  3.    }

  4.    public static Singleton getInstance() {

  5.        return instance;

  6.    }

看了前面两个,在看这个就明显了,在声明的时候就会实例化,也不管需不需要使用。所以一般不推荐使用,可根据应用场景选择。

  • 懒汉式:

 
   
   
 
  1.    private static Singleton instance;

  2.    private Singleton() {

  3.    }

  4.    public static synchronized Singleton getInstance() {

  5.        if (instance == null) {

  6.            instance = new Singleton();

  7.        }

  8.        return instance;

  9.    }

懒汉式式做到了再需要到时候才实例化了,但是每次获取的时候都需要同步,增加了开销,一般不推荐使用这种方式。

说说反射获取

介绍了5种单例方式,不线程安全的就不在这里说了。

除了枚举意外以外的方式,都可以使用反射来获取对象,采用如下方式即可:

 
   
   
 
  1. Class<?> class1 = null;

  2.        try {

  3.            class1 = Class.forName("com.demo.Singleton");

  4.            Method m = class1.getMethod("getInstance");

  5.            Singleton single = (Singleton) m.invoke(null);

  6.            //获取到之后执行

  7.            single.doSomething();

  8.        } catch (ClassNotFoundException e) {

  9.            e.printStackTrace();

  10.        } catch (IllegalAccessException e) {

  11.            e.printStackTrace();

  12.        } catch (NoSuchMethodException e) {

  13.            e.printStackTrace();

  14.        } catch (InvocationTargetException e) {

  15.            e.printStackTrace();

  16.        }

而枚举就不可以咯,会报错的。

所以枚举方式确实很不错。只是在android种不太推荐枚举,官方说到会消耗更多的内存,影响性能问题。对手机内存不大的,是个灾难。


以上是关于简用单例模式的主要内容,如果未能解决你的问题,请参考以下文章

自己写的程序有必要用单例吗

你真的会用单例模式?

为什么要用单例模式?

用单例模式实现主JFrame不变,只有JPanel面板切换

PHP用单例模式实现一个数据库类

这个登录浮窗就适合用单例模式来创建。