坚持每天写博文,记录开发中的点点滴滴
- 饿汉式
饿汉式
饿汉式可以说是我们最先接触单例模式的例子了,是最基本的单例写法,也是最快最懒的方式。
优点:简单好写;缺点:类加载就初始化了对象,影响应用启动速度
package singleton;
/**
*
* @ClassName: BaseSingleton
* @Description: TODO(饿汉式单例模式)
* @author Allen
* @date 2018年1月11日 上午10:08:13
*
*/
public class BaseSingleton {
//第一步:私有构造
private BaseSingleton() {
}
//第二步,私有静态对象
private static BaseSingleton INSTANCE = new BaseSingleton();
//第三步:提供对外获取方法
public static BaseSingleton getBaseSingleton() {
return INSTANCE;
}
}
- 懒汉式 主要是针对于饿汉式的缺点
优点:只有第一次使用时才会初始化对象;缺点:多线程中可能出现创建多个对象
其实就是加了个空判断
package singleton;
/**
*
* @ClassName: LazyLoadSingleton
* @Description: TODO(懒汉式单例)
* @author Allen
* @date 2018年1月11日 上午10:17:27
*
*/
public class LazyLoadSingleton {
//第一步:私有构造
private LazyLoadSingleton() {
}
//第二步:私有静态对象
private static LazyLoadSingleton INSTANCE;
//第三步:如果存在实例给出获取方法,不存在创建
public LazyLoadSingleton getLazyLoadSingleton() {
if(INSTANCE == null) {
INSTANCE = new LazyLoadSingleton();
}
return INSTANCE;
}
}
- 同步锁式
因为懒汉式的出现,虽然解决了饿汉式的不足,但也出现了多线程的问题。于是解决懒汉式的方式就出现了,那就是我们熟知的加锁Synchronized。
优点:保证线程安全;缺点:每次都要加锁,但是获取不经济。
package singleton;
/**
*
* @ClassName: LazySynchronizedSingleton
* @Description: TODO(同步锁式单例)
* @author Allen
* @date 2018年1月11日 上午10:24:02
*
*/
public class LazySynchronizedSingleton {
//第一步:私有构造
private LazySynchronizedSingleton() {
}
//第二步:创建私有对象
private static LazySynchronizedSingleton INSTANCE;
//第三步:提供一个同步的对外获取方法
public static synchronized LazySynchronizedSingleton getInstance() {
if(INSTANCE == null) {
INSTANCE = new LazySynchronizedSingleton();
}
return INSTANCE;
}
}
- 双重检测式
第3种方式应该已经满足日常大部分的需求,但对我们程序员来说,不断的优化才是学习之道。那么针对每次获取都会加锁的问题,要怎么解决呢?双重检测式就出现了。
优点:第一次获取时才会加锁;缺点:相比之下写法麻烦
package singleton;
/**
*
* @ClassName: DoubleCheckSingleton
* @Description: TODO(双重检测单例模式)
* @author Allen
* @date 2018年1月11日 上午10:29:39
*
*/
public class DoubleCheckSingleton {
//第一步:私有构造
private DoubleCheckSingleton() {
}
//第二步:创建静态对象
private static volatile DoubleCheckSingleton INSTANCE;
//提供对外方法
public static DoubleCheckSingleton getInstance() {
if(INSTANCE == null) {
synchronized (DoubleCheckSingleton.class) {
if(INSTANCE == null) {
INSTANCE = new DoubleCheckSingleton();
}
}
}
return INSTANCE;
}
}
我们第二步用到了volatile,关于volatile不是本文的重点,所以这里不展开说明。在第三步中,我们首先判断一次空,如果是空,就加锁,然后再判断一次空,如果为空就创建。这样的好处就是上面优点说到的,只会锁一次。缺点大家也发现了,不仅要必须写volatile,方法中的步骤也不能错。
Java中Volatile关键字详解 https://www.cnblogs.com/zhengbin/p/5654805.html
- 内部类式
优点:懒加载、线程安全、代码少;缺点:暂无
内部类Holder,里面有外部的实例。这怎么就满足懒汉式和线程安全呢?当我们应用初始化时,getInstance没有被调用,就没有实例对象,那就满足了懒汉式。当我们调用getInstance的时候,Java虚拟机为了保证类加载的安全性,所以这里就保证了线程安全。
整理自:详细的双语言(Java与Kotlin)5种单例模式 2018-01-08 FYNN_JASON 码个蛋