设计模式笔记之单例模式的使用

<其它设计模式介绍及案例源码下载 >

简介:单例模式(Singleton Pattern)涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

主要解决:一个全局使用的类实例频繁地创建与销毁。

优点: 1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。 2、避免对资源的多重占用(比如写文件操作)。

缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。

使用场景: 1、Windows 是多进程多线程的,在操作一个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例来进行 2、创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。

实现案例:单例模式根据需要目前比较流行的机种方式为饿汉式(Hungry)、懒汉式(LazyClass)、双检锁(DCLClass)

注意:懒汉式与饿汉式的根本区别在与是否在类内方法外创建自己的对象。并且声明对象都需要私有化,构造方法都要私有化,这样外部才不能通过 new 对象的方式来访问。饿汉式的话是声明并创建对象(因为他饿),懒汉式的话只是声明对象,在调用该类的 getinstance() 方法时才会进行 new 对象。

例如下:

/**
 * 是否 Lazy 初始化:是
 * 是否多线程安全:是
 * 实现难度:易
 * 描述:这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。
 * 优点:第一次调用才初始化,避免内存浪费。 缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。

 */
public class LazyClass {

	private static LazyClass lc;

	private LazyClass() {
		super();
		// TODO Auto-generated constructor stub
	}
	
	public static synchronized LazyClass getInstance() {
		if(lc==null) {
			lc= new LazyClass();
		}
		return lc;
	}
}
/**
 * 是否 Lazy 初始化:否
 *  是否多线程安全:是 
 *  实现难度:易 
 *  描述:这种方式比较常用,但容易产生垃圾对象。
 *   优点:没有加锁,执行效率会提高。
 * 缺点:类加载时就初始化,浪费内存。
 *
 */
public class HungryClass {

	private static  HungryClass lc= new HungryClass();

	private HungryClass() {
		super();
		// TODO Auto-generated constructor stub
	}
	
	public static  HungryClass getInstance() {
		
		return lc;
	}
}
/**
 * 是否 Lazy 初始化:是 
 * 是否多线程安全:是 
 * 实现难度:较复杂
 *  描述:这种方式采用双锁机制,安全相比于懒汉式而言在多线程情况下仍能保持较高性能。
 */
public class DCLClass {

	/*volatile关键字说明:java内存模型规定所有的变量都存放在主内存当
	 * 中,每个线程在执行的时候,会从主内存当中拷贝一份到自己的工作内存当
	 * 中,线程对变量的读取,操作都是在工作内存当中执行的,不同线程之间也
	 * 不能相互访问其他线程的工作内存,线程之间的变量传递需要通过主内
	 * 存来实现共享。那么什么时候把修改过得变量更新到主内存当中去,volatile
	 * 关键字就是为了解决数据一致性的问题,通俗来说就是线程A对变量的修改,会直
	 * 接刷新到主内存,线程B当中,在对变量进行读取的时候,发现变量是volatile关键字
	 * 修饰的变量,直接放弃从工作内存当中读取,而是从主内存中读取
	 */

	private static volatile DCLClass dcl;

	private DCLClass() {
		super();
		// TODO Auto-generated constructor stub
	}
	
	public static  DCLClass getInstance() {
		if (dcl==null) {
			
			synchronized(Class.class) {
				if (dcl==null) {
					dcl=new DCLClass();
				}
			}
		}
		return dcl;
	}
}
public class TestClass {

	public static void main(String[] args) {
		Thread t1=new Thread(new Runnable() {
			@Override
			public void run() {
				int x=0;
				while(x<1000) {
					x++;
					System.out.println("线程一懒汉式:"+LazyClass.getInstance().hashCode());
					System.out.println("线程二饿汉式:"+HungryClass.getInstance().hashCode());
					System.out.println("线程二双检索:"+DCLClass.getInstance().hashCode());
				}
			}
			
		});
		Thread t2=new Thread(new Runnable() {
			@Override
			public void run() {
				int x=0;
				while(x<1000) {
					x++;
					System.out.println("线程二懒汉式:"+LazyClass.getInstance().hashCode());
					System.out.println("线程二饿汉式:"+HungryClass.getInstance().hashCode());
					System.out.println("线程二双检索:"+DCLClass.getInstance().hashCode());
				}
			}
			
		});
		t1.start();
		t2.start();

	}

}

说明:在将输出结果进行排序后,同一种类所创建的对象对应的hashcode值是一致的(同一个对象) 

猜你喜欢

转载自blog.csdn.net/fsy9595887/article/details/84333226
今日推荐