设计模式学习笔记之单例模式

设计模式中最简单的模式就要数单例模式了。

那么什么是单例模式呢? 保证一个类仅有一个实例,并提供一个访问它的全局访问点。



上图为单例模式的结构示意图。


那么为什么要使用单例模式呢?

简单来说:单例模式的存在,一则,解决多线程并发访问的问题二则,节约系统内存,提交系统运行的效率,提高系统性能


下面我们就来看看程序中是怎么实现单例模式的:


一般我们设计一个类都是这样的:


public class Abc
{
	private Abc()
	{
			
	};	
}


然后在其他部分调用:


public class Cbd
{
	public Cbd()
	{
		Abc n1,n2;
		n1=new Abc();
		n2=new Abc();
	}
}


但这样Abc这个类就会出现好多实体并不好控制,下面我们来改变一下啊Abc这个类的结构从而实现单例模式:


public class Abc{
	
	private static Abc uniqeInstance_Abc = null; //通过内置私有静态参数实现单例状态
	
	private Abc(){
		
	};
	
	//外部只能调用单例,单例实体有类内部控制
	public static Abc getInstance_Abc()
	{
		if(uniqeInstance_Abc==null)
		{
			uniqeInstance_Abc=new Abc();
		}
		return uniqeInstance_Abc;
		
	}

}


这样我们变实现了单例模式


public class Cbd
{
	public Cbd()
	{
		Abc n1,n2;
		n1=Abc.getInstance_Abc();
	}
}


可以看到Abc这个类的构造函数变成了private修饰,所以并不能在其他类中new出来只能通过调用getxxx函数来使用,这就保证了单例性。


写一个小例子,模拟一下我们计算机中的CPU处理程序:




package com.java.jikexueyuan.singleton;

public class Cpu {
	private boolean idle;
	private boolean compute;
	public volatile static Cpu uniqueInstance_cpu = null;
	int num;

	private Cpu() {
		idle = true;
		compute = false;
		num = 101;
	}

	public static Cpu getInstance() {

		if (uniqueInstance_cpu == null) {
			synchronized (Cpu.class) {
				if (uniqueInstance_cpu == null) {
					uniqueInstance_cpu = new Cpu();
				}
			}
		}
		return uniqueInstance_cpu;
	}

	//判断cpu是否为空闲状态
	public boolean isIdle() {
		if (idle) {
			idle = false;
			compute = false;
			System.out.println("cpu空闲");
			return true;
		}
		else
		{
			System.out.println("cpu繁忙");
			return true;
		}
	}
	
	//cpu计算结束
	public void compute_over() {
		if ((!idle) && compute) {
			idle = true;
			compute = false;
			System.out.println("cpu计算完成");
		}
	}
	
	//启动cpu计算过程
	public void computing() {
		if ((!idle) && (!compute)) {
			compute = true;
			System.out.println("cpu正在计算,计算cpu编号为" + num);
		}
	}
}

我们来调用一下:


public class test {
	public static void main(String[] args) 
	{
		for(int i = 0; i < 5 ; i++)
		{
			Cpu c1 = Cpu.getInstance();
			if(c1.isIdle())
			{
				c1.computing();
				c1.compute_over();
			}
		}
	}
}



其实这样设计的单例模式有一个重大隐患,就是当两个线程同时创建一个Abc类的时候,可以会new出来两个实体而导致严重的错误。。。


解决传统的解决方式呢,有三种:

第一种:添加同步锁:


public class Abc{
	
	private static Abc uniqeInstance_Abc = null; //通过内置私有静态参数实现单例状态
	
	private Abc(){
		
	};
	
	//外部只能调用单例,单例实体有类内部控制
	//添加了同步所,保证不会有两个线程同是进入该方法
	public static synchronized Abc getInstance_Abc()
	{
		if(uniqeInstance_Abc==null)
		{
			uniqeInstance_Abc=new Abc();
		}
		return uniqeInstance_Abc;
		
	}

}


第二种:急切创建法:

public class Abc{
	
	//通过内置私有静态参数实现单例状态
	//直接创建实例
	private static Abc uniqeInstance_Abc = new Abc();
	
	private Abc(){
		
	};
	
	//外部只能调用单例,单例实体有类内部控制
	public static Abc getInstance_Abc()
	{
		if(uniqeInstance_Abc==null)
		{
			uniqeInstance_Abc=new Abc();
		}
		return uniqeInstance_Abc;
		
	}

}


第三种:双重检查加锁法


public class Abc{
	
	//通过内置私有静态参数实现单例状态
	//volatile关键字确保多线程在处理时的正确性
	private volatile static Abc uniqeInstance_Abc = new Abc();
	
	private Abc(){
		
	};
	
	//外部只能调用单例,单例实体有类内部控制
	public static Abc getInstance_Abc()
	{
		//多重加锁
		if (uniqeInstance_Abc == null) {
			synchronized (Abc.class) {
				if (uniqeInstance_Abc == null) {
					uniqeInstance_Abc = new Abc();
				}
			}
		}
		return uniqeInstance_Abc;
	}
}


单例模式的使用场景:

1.资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置。 
2.控制资源的情况下,方便资源之间的互相通信。如线程池等。 


猜你喜欢

转载自blog.csdn.net/u012269327/article/details/55804675
今日推荐