首页 > 学院 > 开发设计 > 正文

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

2019-11-08 02:24:03
字体:
来源:转载
供稿:网友

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

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

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

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

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

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

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

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.控制资源的情况下,方便资源之间的互相通信。如线程池等。 


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表