首页 > 代码库 > java中的四种单例实现方式

java中的四种单例实现方式

    在java中,单例设计模式是非常常见的设计模式,对单例设计模式的概念,不做过多的介绍,下面将逐一介绍四种单例设计模式:

    1、第一种单例设计模式

    1.1 代码实现

package com.singleton.one;
/**
 * 第一种单例设计模式
 * @author Administrator
 *
 */
public class SingleTonOne {
	// 实例化
	private static SingleTonOne instance = new SingleTonOne();
	
	// 私有构造方法
	private SingleTonOne(){
		System.out.println("---singleton one---");
	}
	
	// 获取单例实例
	public static SingleTonOne getInstance(){
		return instance;
	}
	
	// 静态方法
	public static void hello(){
		System.out.println("---singleton one hello---");
	}
	
}

    1.2 相关测试

package com.singleton.test;

import static org.junit.Assert.assertTrue;

import org.junit.Test;

import com.singleton.one.SingleTonOne;


public class TestSingleTonOne {

	/**
	 * 测试是否是单例
	 */
	@Test
	public void testSingleTonOne(){
		SingleTonOne one1 = SingleTonOne.getInstance();
		SingleTonOne one2 = SingleTonOne.getInstance();
		assertTrue(one1 == one2);
	}
	
	/**
	 * 测试第一种单例的加载方式
	 * 运行结果:
	 * ---singleton one---
	 * ---singleton one hello---
	 * 1、先执行了私有构造方法;
	 * 2、然后再执行静态方法
	 * 结论:
	 * 当单纯的调用静态方法时,调用了私有构造方式是没有必要,也就是
	 * 无法实现懒加载
	 */
	@Test
	public void testSingleTonOneLoad(){
		SingleTonOne.hello();
	}
	
}

    

    2、第二种单例

    2.1 代码实现

package com.singleton.one;
/**
 * 第二种单例设计模式
 * @author Administrator
 *
 */
public class SingleTonTwo {
	
	private static SingleTonTwo instance ;
	
	private SingleTonTwo(){
		System.out.println("-- singleton two --");
	}
	
	/**
	 * 懒加载处理,但是线程不安全
	 * @return
	 */
//	public static SingleTonTwo getInstance(){
//		if (instance == null){
//			instance = new SingleTonTwo();
//		}
//		
//		return instance;
//	}
	/**
	 * 上述注释的getInstance是非线程安全的,该方法做了同步处理;
	 * 但是由于线程处理,往往效率不高
	 */
	public static synchronized SingleTonTwo getInstance(){
		if (instance == null){
			instance = new SingleTonTwo();
		}
		
		return instance;
	}
	
	public static void hello(){
		System.out.println("-- single ton two hello --");
	}
	
}

    2.2 相关测试

package com.singleton.test;

import static org.junit.Assert.assertTrue;

import org.junit.Test;

import com.singleton.one.SingleTonTwo;

/**
 * 测试四种单例方式 -- 第二种单例(懒加载)
 * @author Administrator
 * 
 */
public class TestSingleTonTwo {

	/**
	 * 测试是否是单例
	 */
	@Test
	public void testSingleTonTwo(){
		SingleTonTwo one1 = SingleTonTwo.getInstance();
		SingleTonTwo one2 = SingleTonTwo.getInstance();
		assertTrue(one1 == one2);
	}
	
	/**
	 * 测试第二种单例测试
	 * 运行结果:
	 * -- single ton two hello --
	 * 结论:
	 * 运行静态方法时,不会调用私有构造方法(即:懒加载)
	 */
	@Test
	public void testSingleTonTwoLoad(){
		SingleTonTwo.hello();
	}
}


    3、内部类实现单例

    3.1 代码实现

package com.singleton.one;
/**
 * 内部类实现单例
 */
public class SingleTonThree {
	
	private SingleTonThree(){
		System.out.println("-- SingleTon Three --");
	}
	/**
	 * 内部类实例化
	 * @author Administrator
	 *
	 */
	private static class SingleTonThreeHandler{
		public static SingleTonThree instance = new SingleTonThree();
	}
	
	/**
	 * 通过内部类,获取实例
	 * @return
	 */
	public static SingleTonThree getInstance(){
		return SingleTonThreeHandler.instance;
	}
	
	public static void hello(){
		System.out.println("-- SingleTonThree hello --");
	}
	
	
}

    3.2 相关测试

package com.singleton.test;

import static org.junit.Assert.assertTrue;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

import org.junit.Test;

import com.singleton.one.SingleTonThree;

/**
 * 测试四种单例方式 -- 第三种单例(内部静态类)
 * @author Administrator
 * 
 */
public class TestSingleTonThree {

	/**
	 * 测试是否是单例
	 */
	@Test
	public void testSingleTonThree(){
		SingleTonThree one1 = SingleTonThree.getInstance();
		SingleTonThree one2 = SingleTonThree.getInstance();
		assertTrue(one1 == one2);
	}
	
	/**
	 * 第三种单例测试
	 * 运行结果:
	 * -- SingleTonThree hello --
	 * 结论:
	 * 没有触发构造方法,仅仅执行了方法内部逻辑;实现了懒加载方式。
	 */
	@Test
	public void testSingleTonThreeLoad(){
		SingleTonThree.hello();
	}
}

    4、枚举实现单例

    4.1 代码实现

package com.singleton.one;
/**
 * 枚举类型实现单例
 * @author Administrator
 *
 */
public enum SingleTonEnum {
	/**
	 * 单例实例
	 */
	INSTANCE;
	
	private SingleTonEnum(){
		System.out.println("-- enum singleton --");
	}
	
	public static void hello(){
		System.out.println("-- eum singleton hello --");
	}
	
	
}

    4.2 相关测试

package com.singleton.test;

import org.junit.Test;
import static org.junit.Assert.*;
import com.singleton.one.SingleTonEnum;

/**
 * 测试枚举类型单例
 * @author Administrator
 *
 */
public class TestSingleTonEnum {

	/**
	 * 测试是否是单例
	 */
	@Test
	public void testSingleTonEnum(){
		SingleTonEnum enum1 = SingleTonEnum.INSTANCE;
		SingleTonEnum enum2 = SingleTonEnum.INSTANCE;
		assertTrue(enum1 == enum2);
	}
	/**
	 * 测试是否懒加载
	 * 结果:
	 * -- enum singleton --
	 * -- eum singleton hello --
	 * 该枚举类型,无法懒加载
	 */
	@Test
	public void testSingleTonEnum1(){
		SingleTonEnum.hello();
	}
}


    5、四种单例效率测试

package com.singleton.test;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.singleton.one.SingleTonEnum;
import com.singleton.one.SingleTonOne;
import com.singleton.one.SingleTonThree;
import com.singleton.one.SingleTonTwo;

/**
 * 测试四种单例的效率
 * 运行结果:
 *  ---singleton one---
 *	3
 *	-- singleton two --
 *	57
 *	-- SingleTon Three --
 *  4
 *	-- enum singleton --
 *	3
 * 结果分析:
 * 第二种时间消耗最多,由于其同步处理了,而导致更多的开销
 * @author Administrator
 *
 */
public class TestSingleTon {
	
	long start;
	long end;
	
	@Before
	public void setUp(){
		start = System.currentTimeMillis();
	}

	@Test
	public void testSingleTonOne(){
		for (int i = 0; i < 1000000; i++){
			SingleTonOne instance = SingleTonOne.getInstance();
		}
	}
	
	@Test
	public void testSingleTonTwo(){
		for (int i = 0; i < 1000000; i++){
			SingleTonTwo instance = SingleTonTwo.getInstance();
		}
	}
	
	@Test
	public void testSingleTonThree(){
		for (int i = 0; i < 1000000; i++){
			SingleTonThree instance = SingleTonThree.getInstance();
		}
	}
	
	@Test
	public void testSingleTonEnum(){
		for (int i = 0; i < 1000000; i++){
			SingleTonEnum enum1 = SingleTonEnum.INSTANCE;
		}
	}
	
	
	@After
	public void tearDown(){
		end = System.currentTimeMillis();
		System.out.println(end - start);
	}
	
}


    6、总结

    第一种单例:不具备懒加载的功效;

    第二种单例:懒加载、如果分为线程安全和非线程安全两种,当使用线程安全同步时,会影响效率。

    第三种单例:懒加载、且适合多线程,效率很高;但是可以通过java反射来实例化多个实例,因此在一般情况下,该方式实现比较好;

    第四种单例:必须在jdk5.0以上才具备的,未实现懒加载,多线程友好,并且无法通过java反射来实例化多个实例。

    

    在一般情况下,建议使用第三种和第四种方式。

本文出自 “java程序冥” 博客,请务必保留此出处http://793404905.blog.51cto.com/6179428/1541268