:在类加载的过程中创建单例对象。线程安全,不需要实现锁机制,效率高。不是按需创建的,可能导致加载类时间较长,浪费资源。 饿汉式:线程安全、反射不安全、反序列化不安全 (添加 readResolve 方法后安全)
饿汉式的实现代码如下:
package com.shi.test; import java.io.Serializable; //饿汉模式 public class Single1 implements Serializable{ //私有化当前类对象的实例 private static Single1 instance=new Single1(); //私有化构造方法 private Single1() {}; //对外提供的共有方法 public static Single1 getInstance() { return instance; } //防止反序列化创建新对象 public Object readResolve() { return instance; } }测试代码 如下:
package com.shi.test; import java.lang.reflect.Constructor; import org.junit.Test; public class Single1Test { @Test public void test1() throws Exception{ //1.普通调用 Single1 s1 = Single1.getInstance(); Single1 s2 = Single1.getInstance(); //输出为true System.out.println(s1 == s2); //2.利用反射调用 Class cl = Single1.class; Constructor constructor = cl.getDeclaredConstructor(); constructor.setAccessible(true); Single1 s3 = (Single1) constructor.newInstance(); //输出为false System.out.println(s1 == s3); //3.利用反序列化调用 SerializeUtil.serializeObject(s1); Single1 s4 = (Single1) SerializeUtil.unserializeObject(); //输出为true System.out.println(s1 == s4); } }其中的SerializeUtil定义为:
package com.shi.test; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class SerializeUtil { //用于序列化对象到文件中 public static boolean serializeObject(Object obj) { try(ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new File("a.txt")))){ out.writeObject(obj); out.flush(); out.close(); return true; } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return false; } //反序列化文件到对象中 public static Object unserializeObject() { Object obj = null; try(ObjectInputStream in = new ObjectInputStream(new FileInputStream(new File("a.txt")))){ obj = in.readObject(); in.close(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } return obj; } }:对饿汉式的更改。单例对象不是在类加载的过程中创建,而是在调用 getInstance() 方法的时候创建的,实现了延迟加载的功能。
登记式:线程安全、反射安全(提供检查机制)、反序列化安全(提供 readResolver 方法).
登记式的实现代码为:
package com.shi.test; import java.io.Serializable; //登记式 public class Single2 implements Serializable{ private Single2() { //当instance不为空是若调用构造方法抛出异常 if(SingleHolder.instance != null) { throw new IllegalStateException(); } } //私有化静态内部类 private static class SingleHolder { //私有化静态类成员 private static Single2 instance = new Single2(); } public static Single2 getInstance() { return SingleHolder.instance; } //防止反序列化造成的数据不一致 public Object readResolve() { return SingleHolder.instance; } }测试代码为:
package com.shi.test; import java.lang.reflect.Constructor; import org.junit.Test; public class Single2Test { @Test public void test1() throws Exception{ //1.普通调用 Single2 s1 = Single2.getInstance(); Single2 s2 = Single2.getInstance(); //输出为true System.out.println(s1 == s2); //2.反射调用 Class cl = Single2.class; Constructor constructor = cl.getDeclaredConstructor(); constructor.setAccessible(true); //会抛出异常 // Single2 s3 = (Single2)constructor.newInstance(); //3.反序列化 SerializeUtil.serializeObject(s1); Single2 s4 = (Single2) SerializeUtil.unserializeObject(); //输出为true System.out.println(s1 == s4); //4.多线程访问 for(int i=0;i<20;i++) { new Thread(new Runnable() { @Override public void run() { //输出为同一个对象 System.out.println(Single2.getInstance()); } }).start(); } //防止主程序走的太快 System.in.read(); } }:使用枚举包装类对象,枚举默认支持反射和反序列化安全。 :当类可能有继承关系时不能使用枚举类创建单例模式。 枚举类:线程安全,反射安全,反序列化安全。
实现代码如下:
package com.shi.test; //枚举式 public enum Single3 { //相当于Single3的一个实例对象 INSTANCE{ //重写抽象方法 @Override public void doSome() { System.out.println("----doSomeing"); } }; //创建抽象方法 protected abstract void doSome(); }测试类代码如下:
package com.shi.test; import java.lang.reflect.Constructor; import org.junit.Test; public class Single3Test { @Test public void test1() throws Exception { //1.使用一般调用 Single3 s1 = Single3.INSTANCE; Single3 s2 = Single3.INSTANCE; //输出结果为true System.out.println(s1 == s2); //2.使用反射创建新对象 Class cl = Single3.class; // Constructor constructor = cl.getDeclaredConstructor(); // constructor.setAccessible(true); // Single3 s3 = (Single3)constructor.newInstance(); //结果为抛出异常,enum默认反射安全 // System.out.println(s1 == s3); //3.使用反序列化创建对象 SerializeUtil.serializeObject(s1); Single3 s4 = (Single3) SerializeUtil.unserializeObject(); //enum默认支持反序列化安全 System.out.println(s1 == s4); } }