java与kotlin实现单例模式

单例模式的意义:

确保一个类只有一个实例,而且自行实例化并且向系统提供这个实例。

单例模式的实现条件

①一个private的构造函数,使得这个类只能在内部实例化。
②通过静态方法或者枚举获得单例类对象
③确保单例类有且只有一个,特别是多线程的情况下
④确保单例类对象在反序列化时不会重新构建对象

实现方式

1、饿汉模式
// Java 实现
public class Singleton {
    private static Singleton instance = new Singleton();

    /**
     * 构造私有函数
     */
    private Singleton() {
    }

    /**
     * 公有的静态函数,对外暴露获取单例对象的接口
     */
    public static Singleton getInstance() {
        return instance;
    }
}
//Kotlin实现
object Singleton {
}

其实kotlin已经没有了静态说法了,但kotlin的对象声明,功能上的确是满足了单例模式的实现要求,对象声明的初始化过程是线程安全的。另外,如果你想用kotlin的伴生对象,也是可以的。

饿汉模式很简单,通过私有构造方法和Java的ClassLoader机制来保证单例对象的唯一。

2、懒汉模式

懒汉模式其实就是上面饿汉模式的优化版本,把类的实例化时机延后,在第一次使用的时候才实例化。

public class Singleton {
    private static Singleton instance;

    /**
     * 构造私有函数
     */
    private Singleton() {
    }

    /**
     * 公有的静态函数,对外暴露获取单例对象的接口
     */
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
//Kotlin实现
class SingletonDemo private constructor() {
    companion object {
        private var instance: SingletonDemo? = null
            get() {
                if (field == null) {
                    field = SingletonDemo()
                }
                return field
            }
        @Synchronized
        fun get(): SingletonDemo{
        //instance声明是,会自动创建一个getInstance名字的方法,所以只能换个名字
         return instance!!
        }
    }
}

实例化的代码在可外部调用的getInstance方法里面了,所以要确保单例的唯一性,只能在方法上加上synchronized来进行同步。
缺点也很明显,就是每次调用getInstance方法,都要进行同步,耗费资源。

3、双重校验锁
public class Singleton {
     /**
     * 构造私有函数
     */
    private Singleton() {
    }
    //第一层锁:保证变量可见性
    private volatile static Singleton instance = null;
    /**
     * 公有的静态函数,对外暴露获取单例对象的接口
     */
    public static Singleton getInstance() {
        if (instance == null) {//第一次判空:无需每次都加锁,提高性能
            synchronized (Singleton.class){//第二层锁:保证线程同步
                if (instance == null) {//第二次判空:避免多线程同时执行getInstance()产生多个single对象
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
//kotlin实现
class SingletonDemo private constructor() {
    companion object {
        val instance: SingletonDemo by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
        SingletonDemo() }
    }
}

这里就是用了伴生对象companion object,使得可以用类名的方式来调用instance;
限定构造方法为private,保持实例的唯一性;
使用lazy{}高价函数来实例化,实现了延迟加载,并且lazy函数是线程安全的;
延迟属性lazy语法和解释

4、静态内部类
public class Singleton {
    /**
     * 构造私有函数
     */
    private Singleton() {
    }

    /**
     * 公有的静态函数,对外暴露获取单例对象的接口
     */
    public static Singleton getInstance() {
        return Holder.INSTANCE;
    }

    private static class Holder {
        private static final Singleton INSTANCE = new Singleton();
    }
}
class Singleton private constructor() {
    companion object {
        val instance = Holder.holder
    }

    private object Holder {
        val holder = Singleton()
    }
}

使用静态内部类的方式,是因为双重校验锁有时候也会失效。
看完所有实现方法,kotlin相比Java实在是简单了很多,kotlin语法自身帮我们完成了很多事情。

你可能感兴趣的:(java与kotlin实现单例模式)