单例的五种方式

QuibblerQuibbler 2020-01-08 约 9 分钟 1854 次阅读

单例的五种方式


单例模式是Java开发中常用的模式。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。之前也在学习设计模式的过程中对单例模式有所了解。有两种创建单例的思想,饿汉模式和懒汉模式。除此之外还有几种优秀高效的单例方法。

        “在应用整个生命周期内只能存在一个实例。单例模式是一种被广泛使用的设计模式。他有很多好处,能够避免实例对象的重复创建,减少创建实例的系统开销,节省内存。”

1、饿汉模式

饿汉模式就是立即加载,一般情况下再调用getInstance()方法之前,类加载的时候已经产生了实例。

public class Singleton {
        private static Singleton singleton = new Singleton();
        
        private Singleton() {
        }
        
        public static Singleton getInstance() {
            return singleton;
        }
    }

缺点:占用资源,当单例类很大的时候,其实我们是想使用的时候再产生实例,如果用不到就会白白占用资源。因此这种方式适合占用资源少,在初始化的时候就会被用到的类。

2、懒汉模式

懒汉模式就是延迟加载,也叫懒加载。在程序需要用到的时候再创建实例,这样保证了内存不会被浪费。

2.1、懒汉模式

懒汉模式常规写法如下:

public class Singleton {
        private static Singleton singleton;
        
        private Singleton() {
        }
        
        public static Singleton getInstance() {
            if (null != singleton) {
                singleton = new Singleton();
            }
            return singleton;
        }
    }

缺点:实现方式是线程不安全的,多线程并发的环境下可能出现资源同步问题。导致创建多个单实例对象:

2.2、synchronized懒汉模式

多线程下的资源同步问题一般需要同步,最简单粗暴的方式加个synchronized关键字同步方法。

public class Singleton {
        private static Singleton singleton;
        
        private Singleton() {
        }
        
        public static synchronized Singleton getInstance() {
            if (null == singleton) {
                singleton = new Singleton();
            }
            return singleton;
        }
    }

缺点:效率低,同步运行,下个线程想要取得对象,就必须要等上一个线程释放,才可以继续执行。

即使不同步整个方法,而是仅对其中的部分代码块加锁同步,还是需要同步,效率不高。

public static Singleton getInstance() {
            synchronized (Singleton.class) {
                if (null == singleton) {
                    singleton = new Singleton();
                }
            }
            return singleton;
        }

3、DCL双重检查锁机制 √

DCL(Double Checked Locking,双重检查锁) 双重检查锁机制很好的解决懒加载单例模式的效率问题和线程安全问题。这也是在项目中最常用到的方式。第一次看到师兄的代码单例模式就是这样写的,当时还看不懂,没想到大有文章。

public class Singleton {
        private static volatile Singleton singleton;
        
        private Singleton() {
        }
        
        public static Singleton getInstance() {
            if (null == singleton) 
                synchronized (Singleton.class) {
                    if (null == singleton) {
                        singleton = new Singleton();
                    }
                }
            }
            return singleton;
        }
    }

注意到在定义singleton的时候用到了volatile关键字,这是为了防止指令重排序的,或多或少对性能也有些影响。这样的写法非常讲究,更多参考一篇博客

4、静态内部类(单例最优解) 

靠JVM保证类的静态成员只能被加载一次的特点,这样就从JVM层面保证了只会有一个实例对象。

public class SingletonInner {
        private SingletonInner() {
        }
        
        private static class Singleton{
            private static SingletonInner singletonInner = new SingletonInner();
        }
        
        public static SingletonInner getInstance(){
            return Singleton.singletonInner;
        }
    }

加载一个类时,其内部类不会同时被加载。一个类被加载,当且仅当其某个静态成员(静态域、构造器、静态方法等)被调用时发生。

5、静态代码块 √

和饿汉模式类似

//使用静态代码块实现单例模式
    class SingletonStaticBlock {
        private static SingletonStaticBlock singletonStaticBlock;
        
        static {
            singletonStaticBlock = new SingletonStaticBlock();
        }
        
        public static SingletonStaticBlock getInstance() {
            return singletonStaticBlock;
        }
    }

参考博客:

        Java实现单例的五种方式

相关推荐

精选
获取系统SDK版本、判断手机ROM
Code

获取系统SDK版本、判断手机ROM

Build获取系统SDK版本Android中部分API的使用,需要在特定的SDK版本之后才能使用,因此在兼容老版本SDK的时候,经常需要判断API的版本。各种Android版本的对应关系参考《Android各版本对应的SDK版本》判断手机ROM有时候需要判断手机系统的ROM,检测ROM是MIUI、EMUI还是Flyme,可以使用getprop命令,去系统build.prop文件(关于build.p

3.7k
精选
AndroidStudio中各种中文乱码问题
Code

AndroidStudio中各种中文乱码问题

AndroidStudio中各种中文乱码问题1、编译Java错误信息乱码在出现这个Annotation processors must be explicitly declared now...问题的时候,正好也发现AndroidStudio Build Output错误信息都乱码。经常遇到各种问题,习惯了,现在遇到的问题,都是以后的答案。 1.1、修改项目build.gradle(无效)在整个p

2.4k
AndroidStudio 报错:has no declaration in the base values folder
Code

AndroidStudio 报错:has no declaration in the base values folder

在资源文件中正常定义的值,也能编译运行。昨天还正常,今天一打开就报错。应该又是AndroidStudio自身的Bug了。原因众说纷纭,参考Stack Overflow 一篇类似的讨论。解决:File => Invalidate Caches / Restart => Invalidate and Restart.

4.4k

评论 (1)

评论功能已关闭,仅展示历史评论
Quibbler
Quibbler

单例模板


        阅读ActivityTaskManager源码的时候,看到getService()方法用模板单例对象获取单例,借助android.util.Singleton。

        让我来看看内部的实现,其实很简单,值得参考:

    package android.util
    /**
     * 用于延迟初始化的Singleton帮助器类。
     *
     * 仿照 frameworks/base/include/utils/Singleton.h
     *
     * @hide
     */
    public abstract class Singleton<T> {
        
        private T mInstance;
        protected abstract T create();
        
        public final T get() {
            synchronized (this) {
                if (mInstance == null) {
                    mInstance = create();
                }
                return mInstance;
            }
        }
    }

        由于这个类被Android标记UnsupportedAppUsage,无法使用该类,所以开发中还是需要自己写单例实现。仿照../external/libchrome/base/memory/singleton.h