赞
踩
单例例模式便是创建型设计模式的一种,它确保某一个类在系统中只有一个实例,并自行实例化,同时向外部提供获取这个唯一实例的接口。 单例设计模式主要有以下三个特点:
1、只能有一个实例。
2、必须自己创建自己的唯一实例。
3、必须给所有其他对象提供这一实例。
饿汉设计模式分为两种:
1.静态成员变量的方式
2.静态代码块方式
懒汉设计模式分为六种:
1.懒汉设计模式 (线程不安全)
2.懒汉设计模式 (线程安全,效率低)
3.懒汉设计模式 (双重检查锁模式)volatile 关键字
4.懒汉设计模式(静态内部类模式)
5.懒汉设计模式(序列化破坏单例)readResolve()方法
6.懒汉设计模式(反射破坏单例)
7.懒汉设计模式(枚举)
1.静态成员变量的方式:
/** * 饿汉设计模式 (静态成员变量的方式) */ public class ThehungryDemo { //私有构造方法,外界不能创建对象 private ThehungryDemo() { } // 静态变量进行创建声明 private static ThehungryDemo thehungryDemo=new ThehungryDemo(); //通过公共方法进行创建返回, public static ThehungryDemo getInstance(){ return thehungryDemo; } }
2.静态代码块方式:
/** * 饿汉设计模式 (静态代码块方式) */ public class ThehungryDemo2 { //私有构造方法,外界不能创建对象 private ThehungryDemo2(){ } // 静态变量进行创建声明 private static ThehungryDemo2 thehungryDemo; static { thehungryDemo=new ThehungryDemo2(); } //通过公共方法进行创建返回, public static ThehungryDemo2 getInstance(){ return thehungryDemo; } }
缺点: 以空间换时间,在实例化时就创建,灵活性不高,空间使用率不高。
优点:在类加载过程中便会创建。由此带来的好处是Java的类加载机制本身为我们保证了实例化过程的线程安全性。
1.懒汉设计模式 (线程不安全)
多线程情况下会出现线程不安全
/** * 懒汉设计模式 (线程不安全) */ public class IdlerDemo { //私有无参构造方法 private IdlerDemo() { } // 声明静态的对象 private static IdlerDemo idlerDemo; // 静态的无参获取对象 public static IdlerDemo getInstance(){ // 此处会出现,多线程争抢时间片的情况,导致线程不安全 if (idlerDemo == null) { idlerDemo = new IdlerDemo(); } return idlerDemo; } }
2.懒汉设计模式 (线程安全,效率低)
读写是互斥,但是读和读不互斥
/** * 懒汉设计模式 (线程安全,效率低) * synchronized 关键字 */ public class IdlerDemo { //私有无参构造方法 private IdlerDemo() { } // 声明静态的对象 private static IdlerDemo idlerDemo; // 静态的无参获取对象 // 加入 synchronized 关键字后,保证了线程安全。读写是互斥,但是读和读不互斥 public static synchronized IdlerDemo getInstance(){ if (idlerDemo == null) { idlerDemo = new IdlerDemo(); } return idlerDemo; } }
3.懒汉设计模式 (双重检查锁模式) volatile 关键字重点
volatile 关键字三大特性
1.原子性:一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。
2.可见性:指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。
3.有序性:即程序执行的顺序按照代码的先后顺序执行。
/** * 懒汉设计模式 (双重检查锁模式) */ public class IdlerDemo2 { //声明私有构造方法 private IdlerDemo2() { } // //声明静态的对象 // 不使用volatile关键字 ,在多线程时会报空指针错误 。因为JVM在运行时无法保证有序 // private static IdlerDemo2 idlerDemo2; //声明静态的对象 // volatile 关键字可以保证我们JVM在运行的时候有序进行,保证线程安全 private static volatile IdlerDemo2 idlerDemo2; // 声明公共get()方法 public static IdlerDemo2 getInstance(){ // 在if判断当中加入了synchronized 锁,保证了读读不互斥,提高了效率 if(idlerDemo2 == null){ synchronized (IdlerDemo2.class){ idlerDemo2=new IdlerDemo2(); } } return idlerDemo2; } }
4.懒汉设计模式(静态内部类模式)
JVM在加载外部类的时候,不会加载静态内部类
/** * 懒汉设计模式(静态内部类模式) * JVM在加载外部类的时候,不会加载静态内部类 */ public class IdlerDemo3 { //声明私有构造方法 private IdlerDemo3(){ } //声明静态内部类 ,并给与一个静态常量创建对象。 private static class IdlerDemoHolder { private static final IdlerDemo3 IDLERDEMO= new IdlerDemo3(); } // 获取静态内部类常量创建对象 public static IdlerDemo3 getInstance(){ return IdlerDemoHolder.IDLERDEMO; } }
5.懒汉设计模式(序列化破坏单例)readResolve()方法
通过输入流,输出流破坏单例
/** * 输入流,输出流破坏单例模式 */ public class Test { public static void main(String[] args)throws Exception { writeObjectOutputStream(); IdlerDemo3 idlerDemo3 = writeObjectInputStream(); IdlerDemo3 idlerDemo31 = writeObjectInputStream(); System.out.println(idlerDemo3==idlerDemo31); } /** * 输入流,输入对象 * @throws IOException */ public static void writeObjectOutputStream() throws IOException { IdlerDemo3 instance = IdlerDemo3.getInstance(); ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("F:\\a.txt")); oos.writeObject(instance); oos.close(); } /** * 输出流获取对象 * @return * @throws Exception */ public static IdlerDemo3 writeObjectInputStream()throws Exception{ ObjectInputStream ois = new ObjectInputStream(new FileInputStream("F:\\a.txt")); IdlerDemo3 idlerDemo3=(IdlerDemo3) ois.readObject(); System.out.println(idlerDemo3); return idlerDemo3; } }
解决办法:实现 readResolve()方法
public class IdlerDemo3 implements Serializable { private IdlerDemo3(){ } private static class IdlerDemoHolder { private static final IdlerDemo3 IDLERDEMO= new IdlerDemo3(); } public static IdlerDemo3 getInstance(){ return IdlerDemoHolder.IDLERDEMO; } /** * 查看源码发现,实现序列化接口Serializable之后 * 需要实现readResolve()方法, 序列化底层方法会判断序列化对象有没实现有这个方法, * 如果没有就return新的对象 * @return */ public Object readResolve() { return IdlerDemoHolder.IDLERDEMO; } }
6.懒汉设计模式(反射破坏单例)
问题:反射可以通过突破你的封装,获取你的无参构造方法创建对象。
解决办法:在无参构造方法中加入锁synchronized 保证线程安全,并且加入判断只在第一次突破封装时创建。
public class IdlerDemo3 implements Serializable { //声明一个全局静态变量,初始为false private static Boolean finale=false; private IdlerDemo3(){ // 加上锁, 第一次让他进行创建,第二次就抛异常。防止反射进行获取对象 synchronized (IdlerDemo3.class){ if (finale){ throw new RuntimeException("不能创建多个对象"); } } finale =true; } private static class IdlerDemoHolder { private static final IdlerDemo3 IDLERDEMO= new IdlerDemo3(); } public static IdlerDemo3 getInstance(){ return IdlerDemoHolder.IDLERDEMO; } }
7.懒汉设计模式(枚举)
因为枚举类型是线程安全的,并且只会装载一次。所以枚举设计模式是线程安全的,并且是唯一个不会被破坏的单例实现模式。
/**
* 懒汉模式(枚举),但是还是饿汉式模式(消耗内存)
*/
public enum IdlerDemo4 {
IDLER_DEMO_4;
}
缺点:不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例设计模式就不能保存彼此的状态,导致数据错误。
优点:由于在系统内存中只存在一个对象,因此可以 节约系统资源,当 需要频繁创建和销毁的对象时单例模式无疑可以提高系统的性能。并且可以避免共享资源的多重占用。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。