1.单例模式
1)饿汉式
package com.bjsxt.singleton; public class SingletonDemo1 { //类初始化时,立即加载这个对象(没有延时加载的优势)。加载类时,天然的是线程安全的! private static SingletonDemo1 instance = new SingletonDemo1(); private SingletonDemo1(){ } //方法没有同步,调用效率高! public static SingletonDemo1 getInstance(){ return instance; } }
package com.bjsxt.singleton; public class Client { public static void main(String[] args) { SingletonDemo4 s1 = SingletonDemo4.getInstance(); SingletonDemo4 s2 = SingletonDemo4.getInstance(); System.out.println(s1); System.out.println(s2); } }
2)懒汉式
package com.bjsxt.singleton; public class SingletonDemo2 { //类初始化时,不初始化这个对象(延时加载,真正用的时候再创建)。 private static SingletonDemo2 instance; private SingletonDemo2(){ //私有化构造器 } //方法同步,调用效率低! public static synchronized SingletonDemo2 getInstance(){ if(instance==null){ instance = new SingletonDemo2(); } return instance; } }
3)双重检查锁
package com.bjsxt.singleton; public class SingletonDemo3 { private static SingletonDemo3 instance = null; public static SingletonDemo3 getInstance() { if (instance == null) { SingletonDemo3 sc; synchronized (SingletonDemo3.class) { sc = instance; if (sc == null) { synchronized (SingletonDemo3.class) { if(sc == null) { sc = new SingletonDemo3(); } } instance = sc; } } } return instance; } private SingletonDemo3() { } }
4)静态内部类
package com.bjsxt.singleton; public class SingletonDemo4 { private static class SingletonClassInstance { private static final SingletonDemo4 instance = new SingletonDemo4(); } private SingletonDemo4(){ } //方法没有同步,调用效率高! public static SingletonDemo4 getInstance(){ return SingletonClassInstance.instance; } }
5)枚举式
package com.bjsxt.singleton; public enum SingletonDemo5 { //这个枚举元素,本身就是单例对象! INSTANCE; //添加自己需要的操作! public void singletonOperation(){ } }
其他:
测试懒汉式单例模式(如何防止反射和反序列化漏洞)
package com.bjsxt.singleton; import java.io.ObjectStreamException; import java.io.Serializable; public class SingletonDemo6 implements Serializable { //类初始化时,不初始化这个对象(延时加载,真正用的时候再创建)。 private static SingletonDemo6 instance; private SingletonDemo6(){ //私有化构造器 if(instance!=null){ throw new RuntimeException(); } } //方法同步,调用效率低! public static synchronized SingletonDemo6 getInstance(){ if(instance==null){ instance = new SingletonDemo6(); } return instance; } //反序列化时,如果定义了readResolve()则直接返回此方法指定的对象。而不需要单独再创建新对象! private Object readResolve() throws ObjectStreamException { return instance; } }
测试反射和反序列化破解单例模式
package com.bjsxt.singleton; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class Client2 { public static void main(String[] args) throws Exception { SingletonDemo6 s1 = SingletonDemo6.getInstance(); SingletonDemo6 s2 = SingletonDemo6.getInstance(); System.out.println(s1); System.out.println(s2); //通过反射的方式直接调用私有构造器 // Class<SingletonDemo6> clazz = (Class<SingletonDemo6>) Class.forName("com.bjsxt.singleton.SingletonDemo6"); // Constructor<SingletonDemo6> c = clazz.getDeclaredConstructor(null); // c.setAccessible(true); // SingletonDemo6 s3 = c.newInstance(); // SingletonDemo6 s4 = c.newInstance(); // System.out.println(s3); // System.out.println(s4); //通过反序列化的方式构造多个对象 FileOutputStream fos = new FileOutputStream("d:/a.txt"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(s1); oos.close(); fos.close(); ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/a.txt")); SingletonDemo6 s3 = (SingletonDemo6) ois.readObject(); System.out.println(s3); } }
测试多线程环境下五种创建单例模式的效率
package com.bjsxt.singleton; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.lang.reflect.Constructor; import java.util.concurrent.CountDownLatch; public class Client3 { public static void main(String[] args) throws Exception { long start = System.currentTimeMillis(); int threadNum = 10; final CountDownLatch countDownLatch = new CountDownLatch(threadNum); for (int i = 0; i < threadNum; i++) { new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 1000000; i++) { // Object o = SingletonDemo4.getInstance(); Object o = SingletonDemo5.INSTANCE; } countDownLatch.countDown(); } }).start(); } countDownLatch.await(); // main线程阻塞,直到计数器变为0,才会继续往下执行! long end = System.currentTimeMillis(); System.out.println("总耗时:" + (end - start)); } }