设计模式-单例模式

单例模式是常听说的一种设计模式,它的用法是保证在一个类在任何情况下都只有一个对象,我们常见的有springIOC的applicationContext,数据库的连接池等。
单例模式分为两种:饿汉式和懒汉式。
我们先说饿汉式,饿汉式如其名字一样,像一个饿汉要先创建出一个对象来,来看代码

public class HungurySingle {

	public static HungurySingle hungurySingle = new HungurySingle();
	private HungurySingle(){

	}
	public static HungurySingle getInstance(){
		return hungurySingle;
	}

}
//这是测试类
public class SingleTest {
	public static void main(String[] args) {
		HungurySingle hungurySingle = HungurySingle.getInstance();
		System.out.println(hungurySingle);

		new Thread(() -> {
			HungurySingle hungurySingle12 = HungurySingle.getInstance();
			System.out.println(hungurySingle12);
		}).start();

		new Thread(() -> {
			HungurySingle hungurySingle1 = HungurySingle.getInstance();
			System.out.println(hungurySingle1);
		}).start();

	}
}
运行结果:
com.demo.wqx.partten.single.HungurySingle@36baf30c
com.demo.wqx.partten.single.HungurySingle@36baf30c
com.demo.wqx.partten.single.HungurySingle@36baf30c

代码不难理解,从运行结果来看多线程的情况下也是只有一个对象的。饿汉式的缺点就是不用这个对象也会创建一个对象,浪费空间,接下来来看懒汉式,懒汉式就要稍微复杂一点了,也是像名字一样,这个对象很懒,不会提前把对象创建出来,要需要他的时候才会创建。来看代码

public class LazySingle {
	public static LazySingle lazySingle;

	private LazySingle(){

	}

	/**
	 * 对象为空则new一个,否则直接返回。
	 * @return
	 */
	public static LazySingle getInstance(){
		if(lazySingle == null){
			lazySingle = new LazySingle() ;
		}
		return lazySingle;
	}
}
一个简单的懒汉式单例,就出来了,这里没有写测试类,读者可以思考一下是否有问题,接下来我们来测试一下。
//测试类
public class LazyTest {

	public static void main(String[] args) {
		for (int i = 0; i < 5; i++)
			new Thread(()->{
				LazySingle lazySingle = LazySingle.getInstance();
				System.out.println(lazySingle);
			}).start();
	}
}
运行结果:
com.demo.wqx.partten.single.LazySingle@688ee48d
com.demo.wqx.partten.single.LazySingle@685c0ab0
com.demo.wqx.partten.single.LazySingle@685c0ab0
com.demo.wqx.partten.single.LazySingle@688ee48d
com.demo.wqx.partten.single.LazySingle@688ee48d

看到这里,应该发现问题了吧,上面的代码是线程不安全的,如果有两个线程同时调用这个方法的话,就会new多个对象。解决办法也好说,synchronized关键字可以解决。来看这段代码

	public static synchronized LazySingle getInstance(){
		if(lazySingle == null){
			lazySingle = new LazySingle() ;
		}
		return lazySingle;
	}
	运行结果
com.demo.wqx.partten.single.LazySingle@688ee48d
com.demo.wqx.partten.single.LazySingle@688ee48d
com.demo.wqx.partten.single.LazySingle@688ee48d
com.demo.wqx.partten.single.LazySingle@688ee48d
com.demo.wqx.partten.single.LazySingle@688ee48d

可以看到解决了线程安全的问题,但是我们只是5个线程,如果是500个 5000个线程呢,那么后面的会阻塞很久,显然效率太低了,然后我们再想想优化的方法。这样的话会好很多吧,也就阻塞一次new的时间了。

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

上面基本上就是我们常用的单例模式了,但是synchronized 总归是会浪费性能的,还有其他的方法优化吗?考虑一下内部类

public class LazySingle_two {

	private LazySingle_two(){

	}

	public static final LazySingle_two getInstance(){
		return LazyInnerClassSingleton.lazySingle_two;
	}

	/**
	 * 内部类不初始化的话,不会创建外部类的对象
	 */
	private static class LazyInnerClassSingleton {
		private static final LazySingle_two lazySingle_two = new LazySingle_two();
	}
}

这个留给读者自己测试一下吧,我测试是没有问题的。运行结果就不写出来了。这里貌似没有什么可以优化的了,懒汉式我们也介绍完了,但是单例还有一个问题就是 反射创建对象,上面单例模式的实现方式都是构造方法私有化,但是反射可以强制创建对象。我们再来优化一下刚才通过内部类创建单例对象的方法。

public class LazySingle_two {

	private LazySingle_two(){
		if(LazyInnerClassSingleton.lazySingle_two != null){
			throw new RuntimeException("不允许创建不同单例的对象");
		}
	}


	public static final LazySingle_two getInstance(){
		return LazyInnerClassSingleton.lazySingle_two;
	}

	/**
	 * 内部类不初始化的话,不会创建外部类的对象
	 */
	private static class LazyInnerClassSingleton {
		private static final LazySingle_two lazySingle_two = new LazySingle_two();
	}
}

ok 这样就完美解决反射创建对象的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值