单例设计模式:
调用效率非常频繁,建议采用饿汉;如果创建对象代价很高。则建议采用懒汉 |
饿汉式:
/** * 饿汉单例模式: * 特点: * 线程安全(加载类的时候,天然的线程安全的),调用效率高(不需要同步快) * @author jack * */ public class SingletonDemo01 { //类初始化时,立即加载这个对象(没有延时加载的优势)。加载类时,天然的线程安全。 private static SingletonDemo01 instance=new SingletonDemo01();//类初始化时,立即加载; private SingletonDemo01(){
} public static SingletonDemo01 getInstance(){ return instance; } }
|
懒汉式:
/** * * @author jack * */ public class SingletonDemo02 { //类加载时,不进行初始化该对象,当真正使用时,才进行初始化。 private static SingletonDemo02 instance; private SingletonDemo02(){//私有构造器 } //方法同步,调用效率低 public synchronized SingletonDemo02 getInstance(){ if(null==instance){ instance=new SingletonDemo02(); } return instance; } } OK,加上synchronized关键字之后,getInstance方法就会锁上了。如果有两个线程(T1、T2)同时执行到这个方法时,会有其中一个线程T1获得同步锁,得以继续执行,而另一个线程T2则需要等待,当第T1执行完毕getInstance之后(完成了null判断、对象创建、获得返回值之后),T2线程才会执行执行。——所以这端代码也就避免了Version1中,可能出现因为多线程导致多个实例的情况。 /** * *懒汉模式比较好的方式 */ // Version 4 public class Single4 { private static volatile Single4 instance; private Single4() {} public static Single4 getInstance() { if (instance == null) { synchronized (Single4.class) { if (instance == null) { instance = new Single4(); } } } return instance; } }
|
静态内部类:
/** * 静态内部类的方式,创建单例模式 * 优点: * 线程安全,调用效率高,延迟加载 * @author jack * */ public class SingletonDemo04 { private static class SingleClassInstance{ private static final SingletonDemo04 instance=new SingletonDemo04(); } private SingletonDemo04(){ } public static SingletonDemo04 getInstance(){ return SingleClassInstance.instance; } }
|
枚举:
/** * 通过枚举方式实现单例 * 注意:枚举本身就是单例,由jvm根本保证!避免通过反射和反序列化的漏洞 本身 是线程安全的,而且调用效率也高 * 但是没有延迟加载, * @author jack * */ public enum SingletonDemo05 { /** * 定义一个枚举元素,他代表了一个 实例 */ INSTANCE; /** * 单例可以有自己的操作 */ public void singletonOperation(){ //功能处理 } public static void main(String[] args) { SingletonDemo05 instance = SingletonDemo05.INSTANCE; SingletonDemo05 instance2 = SingletonDemo05.INSTANCE; System.out.println(instance==instance2);//true } }
|
比较好的单例模式具备的优点:
|
通过反射破解单例模式:
通过反序列化破解单例模式:(注意反射和反序列化对于枚举是不起作用的) /** * 测试懒汉式模式。(如何防止反射和反序列化破解枚举) * * @author jack * */ public class SingletonDemo06 implements Serializable { /** * */ private static final long serialVersionUID = -3423017222120593309L; // 类初始化时,立即加载这个对象(没有延时加载的优势)。加载类时,天然的线程安全。 private static SingletonDemo06 instance = new SingletonDemo06();// 类初始化时,立即加载; private SingletonDemo06() { //防止反射 if (instance != null) { throw new RuntimeException(); } } public static SingletonDemo06 getInstance() { return instance; } //反序列化时,如果定义了readResolve则直接返回此方法指定的对象。而 不需要单独再创建对象。(单例模式,避免反序列化创建多个对象,则必须加入这个方法) private Object readResolve() throws ObjectStreamException{ return instance; } } 测试: /** * 测试反射和反序列化破解枚举 * @author jack * */ public class Client02 { public static void main(String[] args) throws Exception { SingletonDemo06 instance = SingletonDemo06.getInstance(); SingletonDemo06 instance2 = SingletonDemo06.getInstance(); System.out.println(instance); System.out.println(instance2); System.out.println(instance == instance2); // 采用反射跳过 // 获取类的注解码文件 /* * Class<SingletonDemo06> clazz * =(Class<SingletonDemo06>)Class.forName("gof23.singleton.SingletonDemo06"); //获取构造器 * Constructor<SingletonDemo06> constructor = clazz.getDeclaredConstructor(); //设置私有变量的可访问性 * constructor.setAccessible(true); //创建对象 SingletonDemo06 instance3 = * constructor.newInstance(); SingletonDemo06 instance4 = constructor.newInstance(); * System.out.println(instance3); System.out.println(instance4); * System.out.println(instance3==instance4); */ // 测试反序列化 FileOutputStream fileOutputStream = null; ObjectOutputStream objectOutputStream = null; try { fileOutputStream = new FileOutputStream("C://copy//a.txt"); objectOutputStream = new ObjectOutputStream(fileOutputStream); objectOutputStream.writeObject(instance); ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("C://copy//a.txt")); SingletonDemo06 instance6 = (SingletonDemo06) objectInputStream.readObject(); System.out.println(instance6); System.out.println(instance6 == instance); } catch (Exception e) { e.printStackTrace(); } finally { if (fileOutputStream != null) { fileOutputStream.close(); } if (objectOutputStream != null) { objectOutputStream.close(); } } } }
单例多线程下的测试: /** * 测试多线程环境下,创建单例模式的效率 * @author jack * */ public class Client3 { public static void main(String[] args) throws Exception { int threadNum=10; final int circleNum=20000000; CountDownLatch countDownLatch = new CountDownLatch(threadNum); ExecutorService threadPool = Executors.newFixedThreadPool(threadNum); long beginTime=System.currentTimeMillis(); for(int i=0;i<threadNum;i++){ threadPool.execute(new Runnable() { @Override public void run() { for(int j=0;j<circleNum;j++){ // SingletonDemo1 singletonDemo1= SingletonDemo1.getInstance(); // SingletonDemo2 singletonDemo2= SingletonDemo2.getInstance(); // SingletonDemo3 singletonDemo3= SingletonDemo3.getInstance(); // SingletonDemo4 singletonDemo4= SingletonDemo4.getInstance(); SingletonDemo5 singletonDemo5= SingletonDemo5.INSTANCE; } countDownLatch.countDown(); // System.out.println(countDownLatch.getCount()); } }); } countDownLatch.await(); long endTime=System.currentTimeMillis(); System.out.println("时间间隔:"+(endTime-beginTime)); threadPool.shutdown(); } }
|
如有疑问,请发邮件:1176306419@qq.com
github:https://github.com/wangrui0/