23中设计模式详解_单利模式

单例模式简介:

单例模式:保证一类只有一个实例,并且对外提供访问该类实例的全局访问点

应用场景:

  • 在个个框架读取配置文件的类,都是单利的
  • 网站的计数器
  • 数据库的连接池的设计Application单利
  • spring中的每个对象默认都是单利的
  • springMVC和struts2也是单列的
优点:单利只产生一个实例,减少了系统性能的开销,当一个对象的产生需要较多资源的时候,就会利用单利来驻留

单列模式实现1:饿汉式

package com.spongeli.signleton;

/**
 * 单列模式--饿汉式
 * 特点:线程安全,效率高,但是没有懒加载的效果
 * @author Administrator
 *
 */
public class SignlitonDemo01 {

	/* 构造器私有化 */
	private SignlitonDemo01(){}
	/* 提供一个私有静态的全局变量对象的实例 */
	private static final SignlitonDemo01 INSTANCE = new SignlitonDemo01();
	/* 对外提供访问的方法 */
	public static SignlitonDemo01 getInstance()
	{
		return INSTANCE ;
	}
}

解释:由于将构造器私有了,外界就无法直接访问类的实例,需要通过对外提供的入口来访问,返回的结果都是类的静态的属性,在初始化类的时候就会初始化该属性,所以线程是天然安全的,所以没有必要在入口处使用synchronzied关键字来锁住方法,所以获取的效率会非常高,但是不会达到懒加载的效果

单例模式实现2:懒汉式

package com.spongeli.signleton;

/**
 * 单列模式--懒汉式
 * 特点:线程安全,获取效率第,但是有懒加载的效果
 * @author Administrator
 *
 */
public class SignlitonDemo02 {

	/* 构造器私有化 */
	private SignlitonDemo02(){}
	/* 提供一个私有静态的全局变量对象的实例 */
	private static SignlitonDemo02 INSTANCE ;
	/* 对外提供访问的方法 */
	public static synchronized SignlitonDemo02 getInstance()
	{
		/* 如果是第一次访问在实例化对象 */
		if(INSTANCE == null)
		{
			INSTANCE = new SignlitonDemo02();
		}
		return INSTANCE ;
	}
}
解释:
由于没有在加载类的时候就将静态私有属性实例化,需要在用户第一次访问的时候在实例化,就需要保证线程是安全的,所以在访问的方法上,必须加上锁,但是加上锁之后,每次访问都会检测是否安全,影响了获取的效率,但是实现了懒加载的效果。线程也是安全的

单例模式实现3:双重检测锁

package com.spongeli.signleton;

/**
 * 双重检测锁
 * 特点:线程安全,获取效率高,也懒加载的效果
 * 但是:由于JVM内部原因,有可能出现不是单利的情况
 * @author Administrator
 *
 */
public class SignlitonDemo03 {

	/* 构造器私有化 */
	private SignlitonDemo03(){}
	/* 提供一个私有静态的全局变量对象的实例 */
	private volatile static  SignlitonDemo03 INSTANCE ;
	/* 对外提供访问的方法 */
	public static  SignlitonDemo03 getInstance()
	{
		/* 如果是第一次访问在实例化对象 */
		if(INSTANCE == null)
		{
			synchronized(SignlitonDemo03.class)
			{
				if(INSTANCE==null)
				{
					INSTANCE = new SignlitonDemo03();
				}
			}
		}
		return INSTANCE ;
	}
}

解释:双重检测锁 是一种使用同步块加锁的方法。程序员称其为双重检查锁,因为会有两次检查 instance == null,一次是在同步块外,一次是在同步块内。为什么在同步块内还要再检验一次?因为可能会有多个线程一起进入同步块外的 if,如果在同步块内不进行二次检验的话就会生成多个实例了

最好的实现方式:内部类:

package com.spongeli.signleton;
/**
 * 内部类的实现机制
 * 特点:线程安全,获取效率高,也有懒加载的效果
 * 但是:由于JVM内部原因,有可能出现不是单利的情况
 * @author Administrator
 *
 */
public class SignlitonDemo04 {

	/* 构造器私有化 */
	private SignlitonDemo04(){}
	/* 创建一个内部类来实现线程的安全,并且实现了懒加载 */
	private static final class  SinglitonDemoInstance{
			public static final SignlitonDemo04 INSTANCE = new SignlitonDemo04();
	}
	/* 提供对外访问的入口 */
	public static SignlitonDemo04 getInstance()
	{
		return SinglitonDemoInstance.INSTANCE;
	}
}
解释:由于使用内部类来初始化对象,所以天然他是线程安全的,当第一次访问时,内部类才会被加载,所以对象初始化,获取到的都是同一个对象

最后一种:枚举实现

package com.spongeli.signleton;
/**
 * 内部类的实现机制
 * 特点:线程安全,获取效率高,也有懒加载的效果
 * 但是:由于JVM内部原因,有可能出现不是单利的情况
 * @author Administrator
 *
 */
public enum SignlitonDemo06 {
	
	INSTANCE;
	
	public void method()
	{
		System.out.println("其他方法--");
	}
}
解释:枚举天生就是单利,而且线程安全,但是没有实现懒加载的效果

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值