单例模式

1、定义

确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例

2、使用场景

确保某个类有且只有一个对象的场景,避免产生多个对象消耗过多的资源,或者某种类型的对象只应该有且只有一个。

3、五种常见的单例模式

1)饿汉单例模式(推荐)

package com.baofeng.singleton;

/**
 * 饿汉单例模式
 * 
 * @author sus
 * 
 * 优点:加载类的时候就创建实例,所以线程安全
 * 缺点:不能延迟加载
 * 典型的空间换时间
 *
 */
public class Singleton {
	private static final Singleton singleton = new Singleton();

	// 构造函数私有化
	private Singleton() {

	}
	
	public void doSomething(){
		System.out.println("do something");
	}

	public static Singleton getInstance() {
		return singleton;
	}
	
	//call
	//Singleton.getInstance().doSomething();
}

2)懒汉单例模式

/**
 * 懒汉单例模式
 * 
 * @author sus
 *
 * 优点:延迟加载
 * 缺点:需要加锁才能实现多线程同步,但是效率会降低
 * 典型的时间换空间
 */
public class Singleton1 {
	private static Singleton1 singleton = null;

	// 构造函数私有化
	private Singleton1() {

	}
	
	public void doSomething(){
		System.out.println("do something");
	}

	public static synchronized Singleton1 getInstance() {
		if(singleton == null){
			singleton = new Singleton1();
		}
		return singleton;
	}
	
	//call
    //Singleton1.getInstance().doSomething();
}

3)双重检查锁定(Doublle Check Lock)单例模式(不太推荐)

/**
 * 双重检查锁定(Doublle Check Lock)单例模式
 * 
 * @author sus
 * 
 * 麻烦,在当前Java内存模型中不一定都管用,(DCL失效问题)某些平台和编译器甚至是错误的,
 * 因为singleton = new Singleton2()这种代码在不同编译器上的行为和实现方式不可预知。
 *
 */
public class Singleton2 {
	//JDK是1.5或之后的版本添加volatile关键字 
	//双重加锁机制的实现会使用一个关键字volatile,
	//它的意思是:被volatile修饰的变量的值,将不会被本地线程缓存,
	//所有对该变量的读写都是直接操作共享内存,从而确保多个线程能正确的处理该变量。
	private volatile static Singleton2 singleton = null;

	// 构造函数私有化
	private Singleton2() {

	}
	
	public void doSomething(){
		System.out.println("do something");
	}

	public static Singleton2 getInstance() {
		//第一层判空是为了避免不必要的同步
		if (singleton == null) {
			synchronized (Singleton2.class) {
				//第二层判空是为了在null的情况下创建实例
				if (singleton == null) {
					singleton = new Singleton2();
				}
			}
		}
		return singleton;
	}
	
	//call
	//Singleton2.getInstance().doSomething();
}

4)静态内部类单例模式(推荐)

/**
 * 静态内部类单例模式
 * 
 * @author sushuai
 *
 *延迟加载,减少内存开销。因为用到的时候才加载,避免了静态field
 *在单例类加载时即进入到堆内存的permanent代而永远得不到回收的缺点(大多数垃圾回收算法是这样)。
 *
 *类级的内部类,也就是静态类的成员式内部类,该内部类的实例与外部类的实例
 * 没有绑定关系,而且只有被调用时才会装载,从而实现了延迟加载
 */
public class Singleton3 {

	// 构造函数私有化
	private Singleton3() {

	}

	public static Singleton3 getInstance() {
		return SingletonHolder.singleton;
	}
	
	public void doSomething(){
		System.out.println("do something");
	}

	private static class SingletonHolder {
	/**
         * 静态初始化器,由JVM来保证线程安全
         */
	  private static final Singleton3 singleton = new Singleton3();
	}
	
	//call
	//Singleton3.getInstance().doSomething();
}


5)包含单个元素的枚举类型的单例模式(极力推荐)

/**
 * 包含单个元素的枚举类型的单例模式
 * 
 * @author sus
 * 
 * 很好,不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。
 * 但是失去了类的一些特性,没有延迟加载,用的人也太少了~~
 */
public enum Singleton4 {

	INSTANCE; //定义一个枚举的元素,就代表Singleton4的一个实例
	
	public void doSomething(){
		System.out.println("do something");
	}
	
	//call
	//Singleton4.INSTANCE.doSomething();
	//单元素的枚举类型已经成为实现Singleton的最佳方法
}
发布了97 篇原创文章 · 获赞 87 · 访问量 32万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览