建立型模式: – 单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式。java
• 结构型模式: – 适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模 式。spring
• 行为型模式: – 模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模 式、解释器模式、状态模式、策略模式、职责链模式、访问者模式数据库
单例模式:编程
• 核心做用: – 保证一个类只有一个实例,而且提供一个访问该实例的全局访问点windows
• 常见应用场景:安全
– Windows的Task Manager(任务管理器)就是很典型的单例模式 – windows的Recycle Bin(回收站)也是典型的单例应用。在整个系统运行过程当中,回收站一直维护着仅有的一个实例。并发
– 项目中,读取配置文件的类,通常也只有一个对象。没有必要每次使用配置文件数据,每次new一个对象去读取。框架
– 网站的计数器,通常也是采用单例模式实现,不然难以同步。jvm
– 应用程序的日志应用,通常都何用单例模式实现,这通常是因为共享的日志文件一直处于打开状态,由于只能有一个实例去操做 ,不然内容很差追加。ide
– 数据库链接池的设计通常也是采用单例模式,由于数据库链接是一种数据库资源。
– 操做系统的文件系统,也是大的单例模式实现的具体例子,一个操做系统只能有一个文件系统。
– Application 也是单例的典型应用
– 在Spring中,每一个Bean默认就是单例的,这样作的优势是Spring容器能够管理 – 在servlet编程中,每一个Servlet也是单例 – 在spring MVC框架/struts1框架中,控制器对象也是单例
单例模式的优势:
– 因为单例模式只生成一个实例,减小了系统性能开销,当一个对象的产生须要 比较多的资源时,如读取配置、产生其余依赖对象时,则能够经过在应用启动 时直接产生一个单例对象,而后永久驻留内存的方式来解决 – 单例模式能够在系统设置全局的访问点,优化环共享资源访问,例如能够设计 一个单例类,负责全部数据表的映射处理
常见的五种单例模式实现方式:
– 主要: • 饿汉式(线程安全,调用效率高。 可是,不能延时加载。)
• 懒汉式(线程安全,调用效率不高。 可是,能够延时加载。)
– 其余: • 双重检测锁式(因为JVM底层内部模型缘由,偶尔会出问题。不建议使用)
• 静态内部类式(线程安全,调用效率高。 可是,能够延时加载)
• 枚举单例(线程安全,调用效率高,不能延时加载)
饿汉式实现(单例对象当即加载)
//饿汉式单例 public class Singleton01 { //类初始化时,当即加载这个对象 //加载类是自然的线程安全的,(没有延时加载的优点) private static Singleton01 instance=new Singleton01(); private Singleton01(){ } //方法没有同步,调用效率高 public static Singleton01 getInstance(){ return instance; } }
懒汉式
//懒汉式 public class Singleton02 { //类初始化时,不初始化这个对象(真正用到的时候在建立) private static Singleton02 instance; private Singleton02(){ //私有构造器 } //方法同步,调用效率低 public static synchronized Singleton02 getInstance(){ if(instance==null){ instance=new Singleton02(); } return instance; } }
双重检索:
//双重检测所机制 //因为编译器优化缘由和jvm底层内部模型缘由,有时候回出现问题 public class Singleton03 { private static Singleton03 instance=null; public static Singleton03 getInstance(){ if(instance==null){ Singleton03 sc; synchronized (Singleton03.class){ sc=instance; if(sc==null){ synchronized(Singleton03.class){ if(sc==null){ sc=new Singleton03(); } } instance=sc; } } } return instance; } private Singleton03(){ } }
静态内部类:
//静态内部类 public class Singleton04 { //要点: //– 外部类没有static属性,则不会像饿汉式那样当即加载对象。 //– 只有真正调用getInstance(),才会加载静态内部类。加载类时是线程 安全的。 //instance是static final 类型,保证了内存中只有这样一个实例存在,并且只能被赋值一次, //从而保证了线程安全性. – 兼备了并发高效调用和延迟加载的优点! private static class Singleton04ClassInstance { private static final Singleton04 instance = new Singleton04(); } private Singleton04() { } public static Singleton04 getInstance() { return Singleton04ClassInstance.instance; } }
枚举模式:
//枚举单例(没有延时加载) public enum Singleton05 { //定义一个枚举,枚举 元素自己就是一个单例 INSTANCE; //添加本身须要的元素 public void singletonOperation(){ } }
public static void main(String[] args) { Singleton01 s1=Singleton01.getInstance(); Singleton01 s2=Singleton01.getInstance(); System.out.println(s1); System.out.println(s2); }
常见的五种单例模式实现方式
– 主要: • 饿汉式(线程安全,调用效率高。 可是,不能延时加载。) • 懒汉式(线程安全,调用效率不高。 可是,能够延时加载。)
– 其余: • 双重检测锁式(因为JVM底层内部模型缘由,偶尔会出问题。不建议使用) • 静态内部类式(线程安全,调用效率高。 可是,能够延时加载) • 枚举式(线程安全,调用效率高,不能延时加载。而且能够自然的防止反射和反序列 化漏洞!) • 如何选用? – 单例对象 占用 资源 少,不须要 延时加载: • 枚举式 好于 饿汉式 – 单例对象 占用 资源 大,须要 延时加载: • 静态内部类式 好于 懒汉式
反射和序列化破坏单例:
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Constructor; public class SingletonTest01 { public static void main(String[] args) throws Exception{ Singleton06 s1=Singleton06.getInstance(); Singleton06 s2=Singleton06.getInstance(); System.out.println(s1); System.out.println(s2); //经过反射的方式直接调用私有构造器 Class<Singleton06> clazz= (Class<Singleton06>)Class.forName("demo.singleton.Singleton06"); //获取无参数构造器 Constructor<Singleton06> c=clazz.getDeclaredConstructor(null); //跳过权限的检查 c.setAccessible(true); Singleton06 s3=c.newInstance(); Singleton06 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")); Singleton06 s5=(Singleton06) ois.readObject(); System.out.println(s5); } }
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Constructor; public class SingletonTest01 { public static void main(String[] args) throws Exception{ Singleton06 s1=Singleton06.getInstance(); Singleton06 s2=Singleton06.getInstance(); System.out.println(s1); System.out.println(s2); //经过反射的方式直接调用私有构造器 Class<Singleton06> clazz= (Class<Singleton06>)Class.forName("demo.singleton.Singleton06"); //获取无参数构造器 Constructor<Singleton06> c=clazz.getDeclaredConstructor(null); //跳过权限的检查 c.setAccessible(true); Singleton06 s3=c.newInstance(); Singleton06 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")); Singleton06 s5=(Singleton06) ois.readObject(); System.out.println(s5); } }
测试:
import java.util.concurrent.CountDownLatch; public class SingletonTest03 { public static void main(String[] args) throws Exception { long start=System.currentTimeMillis(); int threanNum=10; final CountDownLatch countDownLath=new CountDownLatch(threanNum); for(int i=0;i<10;i++){ new Thread(new Runnable(){ @Override public void run(){ for(int i=0;i<1000000;i++){ //Object o=Singleton04.getInstance(); Object o=Singleton05.INSTANCE; } countDownLath.countDown(); } }).start(); } countDownLath.await();//mian线程阻塞,知道计数器变成0,才会继续往下执行 long end=System.currentTimeMillis(); System.out.println("总耗时:"+(end-start)); } }