单例常见实现方式
- 饿汉式:在类被加载时就初始化单例
- 懒汉式:在需要的地方才初始化单例
饿汉式加载问题
传统的在类加载时就创建单例的方法存在一些问题:
1 | class SingleInstance { |
如果类的实例化含义太多的操作,就可能会影响程序的性能,启动时间等。而且如果单例在程序中并未用到,则会一直存在一个无法被GC回收的对象,造成浪费。
如果单例一定会使用,而且构造方法中又没有太多操作,则可以在类加载时就初始化单例。
懒汉式加载问题
下面这种懒加载,在多线程情况下可能会造成创建了多个单例。
线程A正在执行new
操作,线程B同时来获取单例,此时instance
还是null
,线程B就也会去执行new
操作。
1 | class SingleInstance { |
使用synchronized
优化懒加载
- 方式一:对获取方法加锁(不推荐)
1 | public synchronized static SingleInstance getInstance(){ |
这种方式加锁,会造成性能问题。synchronized
修饰了方法,所有线程获取单例时都会经历同步锁,不论单例是否已经被创建。而且获取单例可能是个频繁的操作,直接对方法加锁会降低性能。
- 方式二:双重验证,只对构建加锁
1 | private volatile static SingleInstance mInstance; |
推荐这种方式实现单例懒加载,只当单例没有被构造时才会进入加锁的部分。而且使用volatitle
关键字,让所有线程都能拿到最新的单例。
使用静态内部类优化懒加载
静态内部类只有在被调用时才会被加载,而且静态方法只会执行一次。
1 | class SingleInstance { |
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!