kotlin设计模式(一)创建型- 单例模式

1、饿汉式


object SingletonD {
    val single = 10086
}

等价于java中的:

public class SingletonD {
  public static final SingletonD sInstance = new SingletonD ()
  private SingletonD () {
  }
}

优点:

  • 实现简单
  • 线程安全,因为其在类加载时就进行了初始化,虚拟机内部保证其线程安全,保证对常量/静态变量只进行一次初始化

缺点:

  • 在类加载时就创建了静态对象,实际上可能不会用到,所以对资源来说是浪费了,同时时类的初始化变慢,性能上并不是很好

2、懒汉式

懒汉式就是懒加载,在使用时在进行初始化,其实现如下:

/**
 * 懒汉式
 */
class SingletonD {

    companion object{
        val vInstance by  lazy(LazyThreadSafetyMode.NONE){
            SingletonD()
        }
    }
}

等价于java的:

public class SingletonD{
    private static sInstance;
    
    private SingletonD() {
    }
    
    public static SingletonDgetInstance() {
        if (sInstance == null) {
            sInstance  = new SingletonD()
        }
        return sInstance;
    }
}

优点:

  • 延迟到使用时才进行初始化,提高了类加载的性能

缺点:

  • 非线程安全,多个线程同时访问情况下,会创建多个实例

3、懒汉同步方法式

此方法是在第2中方式上在给房间加锁来实现,如下:

/**
 * 懒汉同步方式式
 */
class SingletonD {

    companion object {
        var sInstance: SingletonD? = null
    }

    @Synchronized
    fun getInstance(): SingletonD? {
        if (sInstance == null) {
            sInstance = SingletonD()
        }
        return sInstance
    }
}

等价于java的:

public class SingletonD{
    private static SingletonDsInstance;
  
    private SingletonD() {
    }
    
    public static synchronized SingletonDgetInstance() {
        if (sInstance == null) {
            sInstance = new SingletonD();
        }
        return sInstance;
    }
}

优点:

  • 延迟到使用时才进行初始化,提高了类加载的性能
  • 对方法使用了同步锁synchronized,保证了线程安全

缺点:

  • synchronized应用在方法上,所有是对整个方法加了锁,所以性能上稍差

4、懒汉同步块式(推荐)

与第3中的方式差不多,不同的是同步锁应用在方法的内部语句块中:
.

class SingletonD{
    companion object {
        val sIntance by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
            SingletonD()
        }
    }
}

等价于java的:

public class SingleC {
    private static SingleC sIntance;
    private SingleC() {
    }
    public static SingleC getInstance() {
        if (sIntance == null) {
            synchronized (SingleC.class) {
                if (sIntance == null) {
                    sIntance = new SingleC();
                }
            }
        }
        return sIntance;
    }
}

优点:

  • 延迟到使用时才进行初始化,提高了类加载的性能
  • 在创建对象的语句块中使用了同步锁synchronized,保证线程安全的同时,降低了锁的作用范围

缺点:

  • 需要1-2次的空判断

5、静态内部类式(推荐)

静态内部类的方式充分使用了语义的规则:

  • 静态的语义规则——》使用到时才进行初始化,实现了懒加载
  • 静态初始化是线程安全,线程的安全由虚拟机内部保证,保证静态初始化时只被初始化一次

以下是kotlin静态内部类的实现方式:

/**
 * 静态内部类(推荐)
 */
class SingletonD {

    companion object{
        fun  getInstance() =InstanceHelper.sSingle
    }

    object InstanceHelper{
        val sSingle = SingletonD()
    }


}

等价于java的:

public class SingleD {
    private SingleD() {

    }
    private static class InstanceHelper {
        static SingleD sInstance = new SingleD();
    }
    public static SingleD getInstance() {
        return InstanceHelper.sInstance;
    }
}

优点:

  • 延迟到使用时才进行初始化,提高了类加载的性能
  • 使用静态初始化虚拟机保证线程安全的特性,实现了线程安全且锁的性能在虚拟机内部实现性能较好

缺点

  • 需要多一个额外的静态内部类来辅助实现

6、总结

综合上述的单例实现就数懒汉同步块式和静态内部类式的性能较好,那如何选择呢?
从其实现的不同方式不难发现:

  • 懒汉同步块式使用1-2两次的判断,所以执行效率相比静态内部类式较差,可以理解为空间优先
  • 静态内部类需要使用一个辅助类来实现,所以空间效率上比懒汉同步块式差,可以理解为空间换执行效率,执行效率优先

那我们该如何抉择呢?

如果空间上没有要求而执行效率上有要求,可以考虑使用静态内部类方式;如果空间上有要求而执行效率有要求,则考虑使用懒汉同步块式;如果空间和执行效率都有要求,需要权衡更需要那种方式而另一种则不得不做出牺牲,比较鱼和熊掌不可兼得;如果空间和执行效率都没有要求,就看个人喜好了。

你可能感兴趣的:(单例模式,kotlin,设计模式)