设计模式介绍与单例模式

设计模式介绍与单例模式,第1张

设计模式介绍与单例模式

文章目录
  • 什么是设计模式
  • 设计模式的分类
    • 创建型模式
    • 结构型模式
    • 行为型模式
  • 什么是单例模式 Singleton
  • 单例模式的结构
  • 单例模式应用场景
  • 单例模式的实现
    • 懒汉模式
      • 懒汉式:线程不安全
      • 懒汉式:线程安全
      • 懒汉式:双重检查锁
      • 懒汉式:静态内部类(这个方法大大的好)
    • 饿汉式
      • 饿汉式特点
      • 饿汉式构造方法1:静态成员变量,在声明的时候直接赋值
      • 饿汉式实现2:静态代码块
      • 饿汉式实现3:枚举类型
  • 单例模式存在的问题
    • 序列化和反序列化破坏单例模式
    • 反射破坏单例模式
  • 单例模式在JDK中的使用
    • Runtime类

什么是设计模式

是一种编程的套路与经验,具有普遍性并可以反复使用。是面向对象设计原则的实际运用,充分体现了类的封装性,继承性多态性与组合关系的充分理解。
P.S: 也是我们程序猿进阶要学的东西

设计模式的分类 创建型模式

描述了怎样创建对象,特点是把对象的创建与使用进行分离,创建型模式提供了1.单例,2.原型,3.工厂方法,4.抽象工厂,建造者等五种创建型模式.

结构型模式

描述如何将类或者对象组成某种更大的结构。包括代理,适配器,桥接,装饰,外观,享元,组合等结构模式

行为型模式

描述类或对象之间如何协作完成单个对象无法完成的任务,以及怎样去分配职责。包括模板方法、策略、命令、职责链、状态、观察者、中介者、迭代器、访问者、备忘录、解释器等11种行为型

什么是单例模式 Singleton

提供了一种创建对象的最佳方式,类创建自己的对象实例,确保单一的类只能创建单一的对象,这个类还提供了单一访问该对象的方式,可以直接访问而不用实例化。这种单例模式有利于节省内存,限制了实例的个数,有利于gc。

单例模式的结构

1.单例类:指只创建一个实例的类
2.访问类:是使用单例类的类

单例模式应用场景

不需要多个实例的使用场景,例如在连接池,线程池中。还有一个所有用户公用的在线人数计数器,类似于b站上的现在观看的人数。

单例模式的实现 懒汉模式

类加载不会导致该实例被创建,在首次使用时才创建对象

懒汉式:线程不安全
public class Singleton{
	//私有的构造方法
	private Singleton(){};
	//声明Singleton类型的变量
	private static Singleton instance;
	//判断该对象是否为空,为空则进行赋值
	public static Singleton getInstance(){
		if(instance==null){
			instance = new Singleton();
		}
		return instance;
	}
}
懒汉式:线程安全
public class Singleton{
	//私有的构造方法
	private Singleton(){};
	//声明Singleton类型的变量
	private static Singleton instance;
	//判断该对象是否为空,为空则进行赋值
	//为避免线程不安全问题,在方法里加上synchronized锁
	public static synchronized Singleton getInstance(){
		if(instance==null){
			instance = new Singleton();
		}
		return instance;
	}
}
懒汉式:双重检查锁

为了避免线程安全方法中加锁所带来的的性能问题,而且getInstance()大部分都是读 *** 作,所以可以不用所有线程都持有锁。

public class Singleton{
	//私有的构造方法
	private Singleton(){};
	//声明Singleton类型的变量
	//为避免多线程的空指针问题,加volatile
	private static volatile Singleton instance;
	//判断该对象是否为空,为空则进行赋值
	public static Singleton getInstance(){
		//第一重检查:如果instance不为null,可直接返回对象不用加锁
		if(instance==null){
			//同步代码块,对字节码加锁
			synchronized(Singleton.class){
				//二重检查
				if(instance==null){
				instance = new Singleton();
				}
			}
		}
		return instance;
	}
}

双重检查锁所带来的问题:多线程时的空指针警告!解决方法:在声明对象时增加volatile关键字

懒汉式:静态内部类(这个方法大大的好)
public class Singleton{
	//私有的构造方法
	private Singleton(){};
	//在静态内部类SingletonHolder中创建实例
	private static class SingletonHolder{
		private static final Singleton INSTANCE = new Singleton();
	}
	//外部访问该对象的方法
	public static Singleton getInstance(){
		//返回的是内部类中的实例
		return Singleton.INSTANCE;
	}
}

在加载Singleton类是不会初始化INSTANCE,只有调用了getInstance()方法时才会在加载内部类SingletonHolder时初始化INSTANCE。该方法在开源项目中常用,没有使用任何锁,既保证了多线程安全,又没有性能影响与空间浪费。

饿汉式

类加载时就创建了对象实例,静态成员变量。

饿汉式特点

1.私有的构造方法
2.在本类中创建本类的对象
3.提供公共的访问方式让外界获取该对象
4.缺陷是类加载时就创建了对象实例,如果一直未使用该对象且比较大时,会造成内存的浪费

饿汉式构造方法1:静态成员变量,在声明的时候直接赋值
//饿汉式:静态成员变量
public class Singleton{
	//私有构造方法
	private Singleton(){};
	//在类中创建对象
	private static Singleton instance = new Sigleton();
	//外界对该对象的访问方式
	public static Singleton getInstance(){
		return instance;
	}
}
饿汉式实现2:静态代码块
//饿汉式:静态代码块
public class Singleton{
	//私有构造方法
	private Singleton(){};
	//声明Singleton类型的变量
	private static Singleton instance;
	//再在静态代码块中对该变量赋值
	static{
		instance = new Singleton;
	}
	//对外提供该类对象的访问方法
	public static Singleton getInstance(){
		return instance;
	}
}
饿汉式实现3:枚举类型
//饿汉式:枚举类型
public enum Singleton{
	INSTANCE;
}

完全线程安全,不会被破坏

单例模式存在的问题

单例模式的破坏:指通过某种方法使Singleton可以创建多个对象。

序列化和反序列化破坏单例模式

解决方法:在Singleton中添加一个readResolve方法,在反序列化中被调用。当进行反序列化中,会自动调用该方法会自动返回。
方法原理: 在源码中定义了如果有readResolve()方法,就会调用该方法的值,如果没有定义就会返回new的对象

反射破坏单例模式

通过反射创建两次对象创建的不是同一个对象
解决方法:添加一个flag来判断是否是第一次创建,如果是第二次创建就抛出异常

单例模式在JDK中的使用 Runtime类

Runtime类是通过饿汉式中的静态成员变量直接赋值实现的

public class Runtime {
    private static Runtime currentRuntime = new Runtime();
​
    
    public static Runtime getRuntime() {
        return currentRuntime;
    }
​
    
    private Runtime() {}
    ...
}

如何使用Runtime类:直接通过Runtime中的getRuntime()来访问而不是new一个。

public class RuntimeDemo {
    public static void main(String[] args) throws IOException {
        //获取Runtime类对象
        Runtime runtime = Runtime.getRuntime();
​
        //返回 Java 虚拟机中的内存总量。
        System.out.println(runtime.totalMemory());
        //返回 Java 虚拟机试图使用的最大内存量。
        System.out.println(runtime.maxMemory());
​
        //创建一个新的进程执行指定的字符串命令,返回进程对象
        Process process = runtime.exec("ipconfig");
        //获取命令执行后的结果,通过输入流获取
        InputStream inputStream = process.getInputStream();
        byte[] arr = new byte[1024 * 1024* 100];
        int b = inputStream.read(arr);
        System.out.println(new String(arr,0,b,"gbk"));
    }
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5573484.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-14
下一篇 2022-12-14

发表评论

登录后才能评论

评论列表(0条)

保存