单例模式

单例模式(singleton)

动机:保证类在系统中只存在一个实例
例:配置文件

public class AppConfig
{
	private String parameterA;
	private String parameterB;
	public String getParameterA() {
		return parameterA;
	}
	public String getParameterB() {
		return parameterB;
	}
	public AppConfig()
	{
		readConfig();
	}
	private void readConfig() {
		// TODO Auto-generated method stub
		Properties p=new Properties();
		InputStream in=null;
		try
		{
			in=AppConfig.class.getResourceAsStream("AppConfig.properties");
			p.load(in);
			this.parameterA=p.getProperty("paramA");
			this.parameterB=p.getProperty("paramB");
	}catch(IOException e)
		{
		 System.out.println("装载配置文件出错");
		 e.printStackTrace();
		}finally
		{
			try {
				in.close();
			}catch(IOException e)
			{
				 e.printStackTrace();
			}
		}
}
}
public class main
{
	public static void main(String[] args) {
	Scanner sc=new Scanner(System.in);
	AppConfig config=new AppConfig();
	String paramA=config.getParameterA();
	String paramB=config.getParameterB();
	System.out.println("paramA="+paramA+",paramB="+paramB);

	}
}

问题:系统运行时,系统会存在很多AppConfig的实例对象,如果配置文件多大,会造成很大的资源浪费。
解决方法:单例模式
保证一个类仅有一个实例,并提供一个访问它的全局访问点。创建一个唯一地变量对象。

class Singleton
{
	private static Singleton instance;
	private Singleton()
	{
		//构造方法为private,外界就不能利用new创建此类型的实例
	}
	public static Singleton GetInstance()
	{//获得本类实例的唯一全局访问点
		if(instance==null)
		{
		//如果实例不存在则new一个新实例,否则返回已有的实例
			instance=new Singleton();
		}
		return instance;
	}
	
}
public class main
{
	public static void main(String[] args) {
	Scanner sc=new Scanner(System.in);
	/*Singleton s0=new Singleton()*/
	//错误,外界不能通过new创建此类型
	Singleton s1=Singleton.GetInstance();
	Singleton s2=Singleton.GetInstance();
if(s1==s2)//判断两次实例化后对象的结果是实例相同
{
	System.out.println("两个对象是相同的实例");
}
else
{
	System.out.println("两个对象是不同的实例");
}
	}
}

单例模式特点:

  • 只能有一个实例
  • 必须自己创建自己的唯一实例
  • 必须给所有其他对象提供这一实例

多线程时的单例

多线程的程序,多个线程同时访问Singleton类,调用GetInstance()方法,有可能造成创建多个实例。
解决:在执行new创建实例的地方加上锁,同时在锁定之前判断下是否为null,这样如果已经创建就不用进入锁了。
java使用synchronized上锁

class Singleton
{
	private static Singleton instance;
	private static final Object syncRoot=new Object();
	//程序运行时创建一个静态只读的进程辅助对象
	private Singleton()
	{
		//构造方法为private,外界就不能利用new创建此类型的实例
	}
	public static Singleton GetInstance()
	{//获得本类实例的唯一全局访问点
		synchronized(syncRoot)//在同一个时刻加了锁的部分程序只有一个线程可以进入
		{
		if(instance==null)
		{
		//如果实例不存在则new一个新实例,否则返回已有的实例
			instance=new Singleton();
		}//不直接synchronized(instance),因为若instance为空,则无法对它加锁
		}
		System.out.println("singleton创建");
		return instance;
	}
}//使得对象实例由最先进入的那个线程创建,以后的线程在进入时不会再去创建对象实例了。由于
//synchronized保证了多线程环境下的同时访问也不会造成多个实例的生成。
public class main
{
	public static void main(String[] args) {
	Singleton s1=Singleton.GetInstance();
	Singleton s2=Singleton.GetInstance();
if(s1==s2)//判断两次实例化后对象的结果是实例相同
{
	System.out.println("该对象的字符串表示形式:");
	System.out.println("s1:"+s1.toString());
	System.out.println("s2:"+s2.toString());
}
	}
}

结果为:

singleton创建
singleton创建
该对象的字符串表示形式:
s1:text.Singleton@52cc8049
s2:text.Singleton@52cc8049
//包名.对象名+@+十六进制的对象的哈希值(JVM虚拟出来的对象内存地址)

在每次调用GetInstance方法时都需要同步,降低了性能
解决:双重锁定

双重锁定

class SingletonDCL
{
	private volatile static SingletonDCL singleton;

	private SingletonDCL()
	{
		
	}
	public static SingletonDCL GetInstance()
	{
		if(singleton==null)
		{//各类加锁,类的所有对象用同一把锁
			synchronized(SingletonDCL.class)
			{
				if(singleton==null)//多线程进入,防止第二个线程创建实例,破坏单例原则
				{
					singleton=new SingletonDCL();
				}
			}
		}
		System.out.println("singleton创建");
		return singleton;
		
	}
}
public class main
{
	public static void main(String[] args) {
	SingletonDCL s1=SingletonDCL.GetInstance();
	SingletonDCL s2=SingletonDCL.GetInstance();
	System.out.println("s1==s2?"+(s1==s2));
	System.out.println("该对象的字符串表示形式:");
	System.out.println("s1:"+s1.toString());
	System.out.println("s2:"+s2.toString());
}
}

结果同样为:

singleton创建
singleton创建
s1==s2?true
该对象的字符串表示形式:
s1:text.SingletonDCL@52cc8049
s2:text.SingletonDCL@52cc8049

单例模式分类

  • 懒汉式(时间换时间):面临多线程的安全问题需要双重锁定
  • 饿汉式(空间换时间):即静态初始化的方法,类一加载就实例化,所有要提前占用系统资源
    使用单例模式的一个必要条件:在一个系统要求一个类只有一个实例
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值