常用Java设计模式系列(1)- 单例模式

    之前一段时间因为一些事情,挺长时间没有再写博客了,可是作为一个二十一世纪的好青年,怎么能半途而废呢,所以,从今天开始,我要继续把我写博客(尤其是技术博客)的传统延续下去,尽量做到每周都更新一篇博文,广大的网友如果有和我是同一个行业的,可以添加下关注,相互交个朋友,相互学习共同进步。


    作为一个技术博客,这里就闲话不多说了,还是以讲述技术为主。从今天起,我将陆续将Java中常见的设计模式做个详细的描述,设计模式有很多种,但是并不是所有的都是我们需要重点关注的,如果不分重要性的全部去了解,不但学不好反而会浪费精力。因此,这我的博文系列里,我只会把常见的设计模式进行比较详细的说明。


    今天,我们就来说一个既重要又比较简单常用的设计模式,那就是单例模式。

    单例模式是什么呢?就是对于某个类,只存在一个实例。

    单例模式的意义在于什么?

    很多时候,对于某个类来说,尤其是提供某项服务的管理类来说,比方说数据库连接池,Http连接池,业务配置项等,这些东西在整个应用的使用过程中其实我们不需要每次使用的时候都去创建一次。我们只需要初始化一次,然后每次使用的时候直接从内容中获取就可以了。


    根据初始化的时机,我们将单例模式分为饿汉式和饱汉式两种类型,他们之间有什么区别呢?

    饿汉式:在应用启动的时候对资源进行初始化,后面需要使用的时候直接拿过来使用;

    懒汉式:在应用启动的时候不进行初始化,而是在该资源第一次被使用的时候才会触发资源的初始化操作,后面如果继续使用则直接从内存中获取;


(1)饿汉式

package com.majing.test.designpattern.singleton;

/**
 * 饿汉式单例模式
 * @author majing
 *
 */
public class EagerSingleton {
	private static EagerSingleton instance = new EagerSingleton();
	private EagerSingleton(){
		super();
	}
	public static EagerSingleton getInstance(){
		return instance;
	}
}

    从上面的实现看,这个EagerSingleton类实现了一个私有无参构造函数,目的是不想给外部的使用方使用new关键字再次创建这个类的实例对象,而是提供了一个public方法来给外部调用获取到已经创建好的唯一实例。类中定义的静态变量instance在这个类被加载的时候就会被创建,且只会被创建一次。


(2)懒汉式

package com.majing.test.designpattern.singleton;

/**
 * 懒汉式单例模式
 * @author majing
 *
 */
public class LazySingleton {
	private static LazySingleton instance;
	private LazySingleton(){
		super();
	}
	public static LazySingleton getInstance(){
		if(instance==null){
			instance = new LazySingleton();
		}
		return instance;
	}
}

从上面的实现看,懒汉式不是在类加载的时候创建实例对象,而是在第一次需要的时候才会去创建这个对象。

    细心的读者可能会注意到一个问题,就是上面的懒汉式单例设计模式,因为是在真正使用的时候才会创建单例对象,那么在多线程的环境下,可能就存在这样的问题,多个线程同时访问这个静态方法,那么可能就会创建多次这个类实例,因此上面的实现并不是线程安全的。这里我们可以使用双重检测加锁的方式来加以解决。对于多线程的问题,在设计模式这个专题博文系列完会后将会开一个专题进行讲述。

    下面我们就将上面的代码实现进行简单的调整:

package com.majing.test.designpattern.singleton;

/**
 * 懒汉式单例模式
 * @author majing
 *
 */
public class LazySingleton {
	private static LazySingleton instance;
	private LazySingleton(){
		super();
	}
	public static LazySingleton getInstance(){
		if(instance==null){
			synchronized (LazySingleton.class) {
				if(instance==null){
					instance = new LazySingleton();
				}
			}
		}
		return instance;
	}
}

    对比一下上面两处的代码,就可以看到,在getInstance()方法中,进行了两次instance==null的判断,并且在第一次判断后增加了一个synchronized关键字的同步化操作,目的在于在多线程环境下,只有一个线程可以真正实现单例对象的创建,从而避免创建多次。


    关于上面讲述的懒汉式和饿汉式两种实现方式,其实有各自的优缺点,下面简单的描述一下:

    饿汉式:在一开始的时候就将资源进行加载和初始化到内存,这样在使用的时候就可以直接获取,也可以避免多线程问题,但是如果初始化需要耗费较多的资源而且可能后面不一定会被使用到,那么将是对资源的一种浪费,饿汉式是一种典型的以空间换取时间的做法;

    懒汉式:和饿汉式恰巧想法,是一种以时间获取空间的做法,只有在真正需要的时候才会加载资源到内存,不会浪费内存,但是如果加载时间过长,将会影响接口的响应速度。


    到此,对于单例模式我们有了比较完整的了解了。接下来我们讲一点拓展的东西,对于懒汉式但是还有没有更好的处理方法呢?

    答案是:Yes!

    喜欢思考的读者应该可以注意到,其实我们这里想解决的是延迟加载和线程不安全的问题矛盾问题。下面我们通过类级内部类和JVM提供的类加载线程安全保证来提供一种新的实现方式:

package com.majing.test.designpattern.singleton;

/**
 * 通过类级内部类和JVM提供的类加载线程安全保证来提供一种新的懒汉式实现方式
 * @author majing
 *
 */
public class LazySingleton2 {
	private LazySingleton2(){
		super();
	}
	private static class LazySingleton2Holder{
		private static LazySingleton2 instance = new LazySingleton2();
	}
	public static LazySingleton2 getInstance(){
		return LazySingleton2Holder.instance;
	}
}

    至此,关于单例模式的相关说明已经全部讲述完毕,如果想了解我最新的博文,请关注我的博客,谢谢。如果您愿意打赏我,可扫描下方二维码,对您的打赏我表示感谢。吐舌头


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值