在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
SingleTonOne instance = SingleTonOne.getInstance();
}
}
@Test
public void testSingleTonTwo(){
for (int i = 0; i
SingleTonTwo instance = SingleTonTwo.getInstance();
}
}
@Test
public void testSingleTonThree(){
for (int i = 0; i
SingleTonThree instance = SingleTonThree.getInstance();
}
}
@Test
public void testSingleTonEnum(){
for (int i = 0; i
SingleTonEnum enum1 = SingleTonEnum.INSTANCE;
}
}
@After
public void tearDown(){
end = System.currentTimeMillis();
System.out.println(end - start);
}
}
6、总结
第一种单例:不具备懒加载的功效;
第二种单例:懒加载、如果分为线程安全和非线程安全两种,当使用线程安全同步时,会影响效率。
第三种单例:懒加载、且适合多线程,效率很高;但是可以通过java反射来实例化多个实例,因此在一般情况下,该方式实现比较好;
第四种单例:必须在jdk5.0以上才具备的,未实现懒加载,多线程友好,并且无法通过java反射来实例化多个实例。
在一般情况下,建议使用第三种和第四种方式。