天天看点

【设计模式一之单例模式】java最全单例模式

###java最全单例模式

定义;

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

实现单例模式有几个比较重要的关键点:

  1. 构造的函数一般不对外进行开放,使用private私有属性
  2. 通过一个静态方法或者枚举返回单例对象
  3. 确保单例类的对象有且只有一个,尤其是在多线程下,一定要保持线程的安全
  4. 确保单例类对象子反序列化的时候不会重新构建对象

单例模式分类:

  • 饿汉式单例模式
  • 懒汉式单例模式
  • 双重检查锁实现单例
  • 静态内部类来实现单例模式
  • 使用枚举类型来实现单例
  • 使用容器的形式来实现单例子模式

饿汉式单例模式

在静态代码块中去new对象, 但是线程不安全,在不使用的时候,其实对象也已经实例化了

package com.example.zzf.single;

import java.io.ObjectStreamException;

/**
 * 饿汉式单例模式
 * 在静态代码块中去new对象,
 * 但是线程不安全,在不使用的时候,其实对象也已经实例化了
 * @author Administrator
 *
 */
public class SingleTonOne {
	
	private static final SingleTonOne singleTonOne = new SingleTonOne();
	
	private SingleTonOne(){
		
	}
	
	public static SingleTonOne getInstance(){
		return singleTonOne;
	}
	
	public void doSomething(){
		System.out.println("this is SingleTonOne");
	}
	
	/**
	 * 防止单例对象在序列化后,再次反序列化后生成不同的对象
	 * @return
	 * @throws ObjectStreamException
	 */
	private Object readResolve() throws ObjectStreamException{
		return singleTonOne;
	}
}
           

####懒汉式单例模式

优点:在实例化的时候去new对象,线程安全

缺点:每一次使用的时候都需要进行同步一次,这样会过多的消耗资源

package com.example.zzf.single;

import java.io.ObjectStreamException;

/**
 * 懒汉式单例模式
 * 优点:在实例化的时候去new对象,线程安全
 * 缺点:每一次使用的时候都需要进行同步一次,这样会过多的消耗资源
 * @author Administrator
 *
 */
public class SingleTonTwo {
	private static SingleTonTwo singleTonTwo;
	
	private SingleTonTwo(){
		
	}
	
	public static synchronized SingleTonTwo getInstance(){
		if(singleTonTwo == null){
			singleTonTwo = new SingleTonTwo();
		}
		return singleTonTwo;
	}
	
	public void doSomething(){
		System.out.println("this is SingleTonTwo");
	}
	
	/**
	 * 防止单例对象在序列化后,再次反序列化后生成不同的对象
	 * @return
	 * @throws ObjectStreamException
	 */
	private Object readResolve() throws ObjectStreamException{
		return singleTonTwo;
	}
}
           

####双重检查锁实现单例

优点:在需要的时候才去实例化,而且能保证线程的安全行,而且单例模式在初始化后,就不会在进行同步,也不会过多的消耗资源

缺点:第一次在加载的时候会加载稍微慢一点,双重检查锁失效可能会出现单例实现有问题

package com.example.zzf.single;

import java.io.ObjectStreamException;

/**
 * 双重检查锁实现单例
 * 有点:在需要的时候才去实例化,而且能保证线程的安全行,而且单例模式在初始化后,就不会在进行同步,也不会过多的消耗资源
 * 缺点:第一次在加载的时候会加载稍微慢一点
 * @author Administrator
 *
 */
public class SingleTonThree {
	private static SingleTonThree sInstance = null;
//	private static volatile  SingleTonThree sInstance = null; //从主内存中读取,会影响性能
	
	private SingleTonThree(){
		
	}
	
	public static SingleTonThree getInstance(){
		if(sInstance == null){
			synchronized (SingleTonThree.class) {
				if(sInstance == null){
					sInstance = new SingleTonThree();
				}
				return sInstance;
			}
		}
		return sInstance;
	}
	
	public void doSomething(){
		System.out.println("this is SingleTonThree");
	}
	
	/**
	 * 防止单例对象在序列化后,再次反序列化后生成不同的对象
	 * @return
	 * @throws ObjectStreamException
	 */
	private Object readResolve() throws ObjectStreamException{
		return sInstance;
	}
	
}
           

静态内部类来实现单例模式

由于双重检查锁在高并发或者因为内存模型的原因,有时候偶尔会失效,所以推荐使用静态内部类来实现单例模式

第一次加载的时候不会初始化SingleTonFour,只有第一次调用getInstance的时候才会去创建对象,

既保证了线程安全性么也保证对象唯一性,同时延迟了单例的实例化

package com.example.zzf.single;

import java.io.ObjectStreamException;

/**
 * 静态内部类来实现单例莫斯
 * 由于双重检查锁在高并发或者因为内存模型的原因,有时候偶尔会失效,所以推荐使用静态内部类来实现单例模式
 * 第一次加载的时候不会初始化SingleTonFour,只有第一次调用getInstance的时候才会去创建对象,
 * 既保证了线程安全性么也保证对象唯一性,同事延迟了单利的实例化
 * @author Administrator
 *
 */
public class SingleTonFour {
	private SingleTonFour(){
		
	}
	
	public static SingleTonFour getInstance(){
		return SingleTonFourHolder.singleTonFour;
	}
	
	private static class SingleTonFourHolder{
		private static final SingleTonFour singleTonFour = new SingleTonFour();
	}
	
	public void doSomething(){
		System.out.println("this is SingleTonFour");
	}
	
	/**
	 * 防止单例对象在序列化后,再次反序列化后生成不同的对象
	 * @return
	 * @throws ObjectStreamException
	 */
	private Object readResolve() throws ObjectStreamException{
		return SingleTonFourHolder.singleTonFour;
	}
}
           

####使用枚举类型来实现单例

好处:枚举在java中就和普通的类型是一样的,不仅能够有字段,还可以有自己的方法,最主要的就是枚举类型实例的创建默认是线程安全的,在任何一种情况下他都只会有一个实例

package com.example.zzf.single;

/**
 * 使用枚举类型来实现单例
 * 好处:枚举在java中就和普通的类型是一样的,不仅能够有字段,还可以有自己的方法,最主要的就是枚举类型实例的创建默认是线程安全的,在任何一种情况下他都只会有一个实例
 * 
 * @author Administrator
 *
 */
public enum SingleTonEnum {
	INSTANCE;
	public void doSomething(){
		System.out.println("this is SingleTonEnum!");
	}
}

           

####使用容器的形式来实现单例子模式

将多个单例类型全部注入到一个管理类中进行统一管理,根据需求来选择

package com.example.zzf.single;

/**
 * 使用容器的形式来实现单例子模式
 * 将多个单例类型全部注入到一个管理类中进行统一管理,根据需求来选择
 * 
 */
import java.util.HashMap;
import java.util.Map;

public class SingleTonManager {
	private static Map<String,Object> objectMap = new HashMap();
	
	private SingleTonManager(){
		
	}
	
	public static  void registerSingleServer(String key,Object instance){
		if(!objectMap.containsKey(key)){
			objectMap.put(key, instance);
		}
	}
	
	public static Object getSingleService(String key){
		return objectMap.get(key);
	}
	
}
           

MainTest.java中的代码:

package com.example.zzf;

import com.example.zzf.single.SingleTonEnum;
import com.example.zzf.single.SingleTonFour;
import com.example.zzf.single.SingleTonManager;
import com.example.zzf.single.SingleTonOne;
import com.example.zzf.single.SingleTonThree;
import com.example.zzf.single.SingleTonTwo;

public class MainTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		SingleTonOne singleTonOne = SingleTonOne.getInstance();
		singleTonOne.doSomething();
		SingleTonManager.registerSingleServer("SingleTonOne", singleTonOne);
		
		SingleTonTwo singleTonTwo = SingleTonTwo.getInstance();
		singleTonTwo.doSomething();
		SingleTonManager.registerSingleServer("SingleTonTwo", singleTonTwo);
		
		SingleTonThree singleTonThree = SingleTonThree.getInstance();
		singleTonThree.doSomething();
		SingleTonManager.registerSingleServer("SingleTonThree", singleTonThree);
		
		SingleTonFour singleTonFour = SingleTonFour.getInstance();
		singleTonFour.doSomething();
		SingleTonManager.registerSingleServer("SingleTonFour", singleTonFour);
		
		SingleTonEnum singleEnum = SingleTonEnum.INSTANCE;
		singleEnum.doSomething();
		SingleTonManager.registerSingleServer("SingleTonEnum", singleEnum);
		
		System.out.println("===========================================");
		singleTonOne = (SingleTonOne) (SingleTonManager.getSingleService("SingleTonOne"));
		singleTonTwo = (SingleTonTwo) SingleTonManager.getSingleService("SingleTonTwo");
		singleTonThree = (SingleTonThree) SingleTonManager.getSingleService("SingleTonThree");
		singleTonFour = (SingleTonFour) SingleTonManager.getSingleService("SingleTonFour");
		singleEnum =	(SingleTonEnum) SingleTonManager.getSingleService("SingleTonEnum");
		singleTonOne.doSomething();
		singleTonTwo.doSomething();
		singleTonThree.doSomething();
		singleTonFour.doSomething();
		singleEnum.doSomething();		
	}
}
           

这些都是一些很简单的理解和总结,希望这些能够帮助到大家:

源码下载地址:源代码下载