设计模式介绍与单例模式笔记

什么是设计模式

是一种编程的套路与经验,具有普遍性并可以反复使用。是面向对象设计原则的实际运用,充分体现了类的封装性,继承性多态性与组合关系的充分理解。
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();/**
     * Returns the runtime object associated with the current Java application.
     * Most of the methods of class <code>Runtime</code> are instance
     * methods and must be invoked with respect to the current runtime object.
     *
     * @return  the <code>Runtime</code> object associated with the current
     *          Java application.
     */
    public static Runtime getRuntime() {
        return currentRuntime;
    }/** Don't let anyone else instantiate this class */
    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"));
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值