设计模式之单例模式

1.饿汉式

/*
 * 1.简单且线程安全
 * 2.加载会增加耗时
 * 3.如果此类未使用到, 则会一直空闲浪费空间
 * 4.final可省去
 */
public class TestSingleton {
	private static final TestSingleton testSingleton = new TestSingleton();
	private TestSingleton {};
	public static TestSingleton getInstance() {
		return testSingleton;
	}
}

2.懒汉式

静态代码块:

// 线程不安全
public class TestSingleton {
	private static TestSingleton testSingleton;
	private TestSingleton {};
	static {
		try{
            testSingleton= new TestSingleton();
        }catch(Exception e){
            throw new RuntimeException("Exception occured in creating singleton instance");
        }
	}
	public static TestSingleton getInstance() {
		return testSingleton;
	}
}
// 线程安全
public class TestSingleton {
	private static TestSingleton testSingleton;
	private TestSingleton {};
	public static synchronized TestSingleton getInstance() {
		if (testSingleton == null) {
			testSingleton = new TestSingleton();
		}
		return testSingleton;
	}
}

3.静态内部类(Bill Pugh)

// 线程安全
public class TestSingleton {
	private TestSingleton {};
	private static class InnerObject {
		// final可省去
		private static final TestSingleton INSTANCE = new TestSingleton();
	}
	public static TestSingleton getInstance() {
		return InnerObject.INSTANCE;
	}
}

4.双重检查锁(Double Checked Locking)

/**
 * 优化了懒汉模式的性能
 * 但这缺存在一个不易察觉的错误:无法达到同步
 */
public class TestSingleton {
	private static TestSingleton testSingleton;
	private TestSingleton {};
	public static TestSingleton getInstance() {
		synchronized (TestSingleton.class) {
			if (testSingleton == null) {
				testSingleton = new TestSingleton();
			}
			return testSingleton;
		}
	}
}

为什么说达不到同步呢?
多线程时, 处理器和编译器为了提高程序的性能会发生指令重排.
例如:

TIMEThread1Thread2
T1检查testSingleton是否为空
T2获取锁
T3再次检查testSingleton是否为空
T4为testSingleton分配空间
T5将testSingleton指向内存空间
T6检查到testSingleton不为空
T7访问testSingleton(此时对象还未完成初始化)
T8初始化testSingleton

在这种情况下,T7时刻线程2对testSingleton的访问,访问的是一个初始化未完成的对象。
使用了volatile关键字后,重排序被禁止,所有的对其写(write)的操作都将发生在读(read)操作之前。

/**
 * 1.优化了锁机制所产生的性能消耗
 * 2.真正实现了同步
 */
public class TestSingleton {
	private volatile static TestSingleton testSingleton;
	private TestSingleton {};
	public static TestSingleton getInstance() {
		if (testSingleton == null) {
            synchronized (TestSingleton.class) {
                if (testSingleton == null) {
                    testSingleton = new TestSingleton();
                }
            }
        }
        return testSingleton;
	}
}

5.枚举

public enum TestSingleton {

    // 枚举元素本身就是单例
    INSTANCE;

    // 添加自己需要的操作, 直接通过TestSingleton.INSTANCE.doSomething()的方式调用即可
    // 此方法方便、简洁又安全
    public void doSomething() {
        System.out.println("...");
    }
}

6.额外补充

1.单例模式的破坏

除了枚举以外的其他几种方式, 均能使用反射进行破坏
对于破坏行为, 个人认为, 既然编程者需要新的示例而使用此方法, 大可不必去限制
当然如果想限制, 只需在私有构造方法中加入简单的NULL判断即可
例如:

private TestSingleton {
	if (testSingleton != null) {
		throw new RuntimeException("...");
	}
};

2.工具类用单例模式还是静态方法

  • 如果没有配置信息的工具类, 选静态类,随处调用,不需引用.
  • 如果有配置信息的工具类,最好还是使用单例模式. 如: 多数据源
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值