设计模式之单例模式

单例模式的几种写法和优缺点

  1. 饿汉式 静态常量

/**
 * 饿汉式  静态常量
 * <p>在类加载的时候,就已经初始化,无论之后用没用到。这样写法简单,所以
 * 优点:<p> 写法简单,避免多线程的同步问题
 * <p>
 * 劣:<p> 没有达到懒加载的效果 消耗过多的内存
 */
class Singleton {
    /**
     * 类的内部创建 对象 static final
     */
    private static final Singleton instance = new Singleton ();

    /**
     * 构造器私有化  防止外部用 构造器
     */
    private Singleton () {

    }

    public static Singleton getInstance() {

        return instance;
    }

}

2:懒汉式

1:线程不安全

/**
 * 懒汉式  线程不安全
 * 
 * <p>
 * 优:<p> 与饿汉式单例不同的是,懒汉式单例是要在用到的时候才实例化 实现了懒加载 也不会消耗内存
 * <p>
 * 劣:<p> 但是在多线程的情况下会出现线程不安全情况,可能会出现 回去的实例不是一个对象
 */
class Singleton {
    private Singleton () {
    }

    private static Singleton instance;

    public synchronized  static  Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton ();
        }
        return instance;
    }
}



2:懒汉式 同步方法

/**
 * 懒汉式  同步方法
 * <p>
 * 优:<p> 添加了synchronized  解决了线程安全的问题
 * <p>
 * 劣:<p> 多个线程在获取实例时,只能有一个线程能获取到锁,调用getInstance()方法,其他线程会被阻塞在外边。效率太低
 */
class Singleton {
    private Singleton () {
    }

    private static Singleton instance;

    public synchronized static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton ();
        }
        return instance;
    }
}

3:懒汉式  同步代码块

/**
 * 懒汉式  同步代码块
 * <p>
 * 为了不让线程在方法外等待,而是实例不为空就直接返回,可以这么改写getInstance()方法:
 *
 * <p> 不推荐 :解决不了线程安全问题
 */
class Singleton {
    private Singleton () {
    }

    private static Singleton instance;

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

3 :双重检查机制

但是发现得到的并不是同一个对象,这是因为当一个线程进入synchronize中的代码块时,还没来得及实例化,另一个线程判断(singleton==null)进入if语句,但是没获取到锁,在外面等待,当前一个线程实例化完后,释放了锁,后一个线程拿到锁继续执行,又实例化了一个对象。所以这样写不是线程安全的。

优点

线程安全

解决了线程安全问题

懒加载

不会造成内存的浪费

效率高

效率相对较高

缺点:

可能会出现初始化为空的情况出现

/**
 * 双重检查机制
 * <p> 推荐使用
 * <p>
 * 优:<p>
 *      线程安全
 *      解决了线程安全问题
 *      懒加载
 *      不会造成内存的浪费
 *      效率高
 *      效率相对较高
 */
class Singleton {
    private Singleton() {
    }

    private static Singleton instance;

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

但是 在jvm中,new操作并不是原子性的,一个new语句包括了:

1.给instance分配空间

2.调用 Singleton 的构造函数来初始化

3.将instance对象指向分配的内存空间

在JVM中的及时编译存在指令重排序的优化,也就是说,上述执行顺序不能保证,如果第一个线程在实例化对象时,2执行在3前边,当线程执行完2,singleton就已经非空了,如果其他线程在第一个线程为执行完3之前,调用getInstance()方法将获取到一个不完整的对象(未初始化),使用则会报错。如:排序

1.给instance分配空间

2.将instance对象指向分配的内存空间

3.调用 Singleton 的构造函数来初始化

所以需要volatile关键字修饰singeton,禁止JVM进行指令重排序。(这是最正确的写法,要记住)

/**
 * 双层检查机制 
 * 
 */
class Singleton {
    private static volatile Singleton instance = null;

    private Singleton() {
    }

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

 

*********************************************************************************************************************************************

JAVA 式 kotlin 单例  能使用在kotlin 代码中

 

/**
 * 懒加载
 */
class Singleton {
    companion object {
        private var instance: Singleton? = null
        fun getInstance(): Singleton {
            if (instance == null) {
                instance = Singleton ()
            }
            return instance!!
        }
    }
}

线程安全

/**
 * 懒加载  线程安全
 */
class Singleton {
    companion object {
        private var instance: Singleton? = null
        @Synchronized
        fun getInstance(): Singleton{
            if (instance == null) {
                instance = Singleton()
            }
            return instance!!
        }
    }
}

双重锁

/**
 * 懒加载  双重 锁
 */
class Singleton {
    companion object {
        @Volatile
        private var instance: Singleton? = null
        fun getInstance(): Singleton{
            synchronized(this) {
                if (instance == null) {
                    instance = Singleton()
                }
            }
            return instance!!
        }
    }
}

kotlin 代码 单例

/**
 * 懒汉式 kotlin 模板的 推荐  by lazy
 */
class Singleton private constructor() {
    companion object {
        // 默认是加锁的
        val getInstance: Singleton by lazy {
            DoubleCheckSin()
        }
    }
}

与上面的区别是 可在 by lazy 中设置模式

class Singleton private constructor() {
    companion object {
        //LazyThreadSafetyMode.NONE 没有锁   SYNCHRONIZED 加锁   不写NONE  默认情况下是加锁的模式
        val instance by lazy(LazyThreadSafetyMode.NONE) {
            Singleton()
        }
    }
}

静态内部类

/**
 * 静态内部类
 */
class InnerSin constructor() {

    companion object {
        val instance = Holder.holder
    }

    private object Holder {
        val holder = InnerSin()

    }
}

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值