设计模式
- 创建型模式:
单列模式/工厂模式/抽象工厂模式/建造者模式/原型模式 - 结构型模式
适配器模式/桥接模式/装饰模式/组合模式/外观模式/代理模式 - 行为型模式
模板方法模式/命令模式/迭代器模式/观察者模式/中介者模式/备忘录模式/解释器模式/状态模式/策略模式/责任链模式/访问者模式.
1.单列模式
1.核心: 保证一个类只有一个实例,并提供一个访问该实例的全局访问点.
2.创建的应用场景:
任务管理器/回收站/读取配置文件/网站计数器/数据库连接池/操作系统的文件系统/Servlet编程中(Application对象)/Spring中bean /springmvc或Struts中的控制器对象...
3. 单列模式优点:
(1)减少系统开销,如读取配置文件..
(2)可以在系统设置全局的访问点,优化共享资源访问.
2.创建5种单列模式实现方式
1. 恶汉式(线程安全,调用效率高.但是不能延时加载)
2.懒汉式(线程安全,调用效率不高.但是可以延迟加载)
3.双重检测锁式(由jvm底层内部模型)
4.静态内部类式(线程安全,调用效率高,但是可以延时加载)
4.枚举类(线程安全,调用效率高,不能延时加载)
eg.
1.恶汉式
package com.zhihui.singleton;
/**
* 测试恶汉式单例模式
* @author xzb_l
*
*/
public class SingletonDemo1 {
// 私有该对象,初始化给静态属性(类初始化时,立即加载,没有延时加载的优势;加载类的时候,会线程安全)
private static SingletonDemo1 instance = new SingletonDemo1();
// 私有构造器
private SingletonDemo1() {}
/**
* 提供公共访问方法(不需要使用synchronize关键字,效率高)
*/
public static SingletonDemo1 getInstance() {
return instance;
}
}
2.懒汉式
/**
* 测试懒汉式单例模式
* @author xzb_l
*
*/
public class SingletonDemo2 {
// 私有该对象,不初始化延时加载,使用时再创建
private static SingletonDemo2 instance;
// 私有构造器
private SingletonDemo2() {}
/**
* 提供公共访问方法(方法同步,调用效率低)
*/
public static synchronized SingletonDemo2 getInstance() {
if (instance == null) {
instance = new SingletonDemo2();
}
return instance;
}
}
双重检测锁实现
/**
* 双重检测锁
* @author xzb_l
*
*/
public class SingletonDemo3 {
private static SingletonDemo3 instance = null;
// 私有构造器
private SingletonDemo3() {}
/**
* 只需要在第一次的时候同步
* @return
*/
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;
}
}
静态内部类方式实现(也是一种懒加载)
******
/**
* 静态内部类实现单利模式
* 这种方式线程安全,调用效率高,并且实现了延时加载
* @author xzb_l
*
*/
public class SingletonDemo4 {
// 静态内部类
private static class SingletonClassInstance{
private static final SingletonDemo4 instance = new SingletonDemo4();
}
// 私有构造器
private SingletonDemo4() {}
/**
* 调用的时候加载
* @return
*/
public static SingletonDemo4 getInstance() {
return SingletonClassInstance.instance;
}
}
枚举方式(天然单例)
/**
* 枚举方式实现单例模式
* @author xzb_l
*
*/
public enum SingletonDemo5 {
// 这个枚举元素本身就是单例对象 类名.INSTANCE 即可(但是没有懒加载的效果)
INSTANCE;
/**
* 可以对该单列做其他操作
*/
public void singletonOperation(){
// 处理
}
}
选择
单例对象 占用资源少 ,不需要延时加载;
- 枚举 好于 恶汉式
单例对象 占用资源大,需要延时加载;
- 静态内部类 好于 懒汉式
反射和反序列化漏洞
反射可以破解上面几种实现方式(除枚举方式)
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamException; import java.io.Serializable; import java.lang.reflect.Constructor; /** * 如何防止反序列化和反射漏洞 * @author xzb_l * */ public class SingletonDemo6 implements Serializable { /** * */ private static final long serialVersionUID = 1L; // 静态内部类 private static class SingletonClassInstance{ private static final SingletonDemo6 instance = new SingletonDemo6(); } // 私有构造器 private SingletonDemo6() { if (SingletonClassInstance.instance == null) { try { throw new Exception("防止反射"); } catch (Exception e) { e.printStackTrace(); } } } /** * 调用的时候加载 * @return */ public static SingletonDemo6 getInstance() { return SingletonClassInstance.instance; } public static void main(String[] args) throws Exception { // 反射方式 Class<SingletonDemo6> clazz = (Class<SingletonDemo6>) Class.forName("com.zhihui.singleton.SingletonDemo6"); Constructor<SingletonDemo6> c = clazz.getDeclaredConstructor(null); c.setAccessible(true);// 跳过检查 SingletonDemo6 newInstance1 = c.newInstance(); SingletonDemo6 newInstance2 = c.newInstance(); System.out.println(newInstance1 == newInstance2); SingletonDemo6 s1 = SingletonDemo6.getInstance(); System.out.println("---------------"); // 序列化方式 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(s1 == s3); // 新的 } /** * 防止反序列化漏洞 * 反序列化的时候,直接调用这个方法,返回此对象,而无需把读取的新对象返回. * (基于回调,反序列化时该类有此方法则会自动调用该方法) */ private Object readResolve() throws ObjectStreamException { return SingletonClassInstance.instance; } }
5中单列模式,在多线程环境下的效率测试
借助类 CountDownLatch类:
同步类在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待
- countDown() 当前线程调用此方法,则计数减一(建议放在finally里执行)
- await() 调用此方法会一直阻塞当前线程,知道计时器的值为0
import java.util.concurrent.CountDownLatch;
/**
* 测试多线程下单例模式效率
* @author xzb_l
*
*/
public class TestClient {
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 < 10000; i++) {
Object o = SingletonDemo1.getInstance(); // 测试恶汉式
}
// 执行完,减一
countDownLatch .countDown();
}
}).start();
}
// 主线程等待,直到计数器为0
countDownLatch.await();
long end = System.currentTimeMillis();
System.out.println("总耗时:"+(end-start));
}
}