单例模式

简介

​ 这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式,这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

注意

  • 单例类只能有一个实例;
  • 单例类必须自己创建自己的唯一实例;
  • 单例类必须给所有其他对象提供这一实例;

作用:某个类在整个系统中只能有一个实例对象可以被获取和使用

优点

  • 只生成一个实例,减少系统性能开销;
  • 可以在系统设置全局访问点,优化共享资源访问;

缺点

  • 没有接口
  • 不能继承
  • 与单一职责原则冲突
  • 一个类应该只关心内部逻辑,而不关心外面怎么样来实例化

使用场景

​ 单例模式保证了系统内存中该类只存在一个对象,节省了系统资源。对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能,(比如工具类对象、频繁访问数据库或文件的对象)

注意:当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用new;


synchronized关键字

在Java中,synchronized锁可能是我们最早接触的锁了

synchronized的作用

  1. 锁住类
  2. 锁住对象实例

synchronized的3个用法

  1. 静态方法加上关键字:那么它获取的就是这个类的锁,锁住的就是这个类
  2. 实例方法(也就是普通方法)加上关键字:那么它获取的就是这个累的锁,锁住的就是这个对象实例
  3. 方法中使用同步代码块(性能好)

volatile关键字

volatileJava提供的一种轻量级的同步机制,在并发编程中,它也扮演着比较重要的角色同synchronized相比(synchronized通常称为重量级锁),volatile更轻量级。

可见性

所谓可见性,是指当一条线程修改了共享变量的值,新值对于其他线程来说是可以立即得知的。很显然,上述的例子中是没有办法做到内存可见性的。


实现

方式

  1. 饿汉式(线程安全,调用效率高,不能延时加载)
  2. 懒汉式(线程安全,调用效率不高,能延时加载)
  3. 懒汉式-双重检查锁式(JVM底层内部模型原因,偶尔会出问题)
  4. 静态内部类式(线程安全,调用效率高,能延时加载)
  5. 枚举单例(线程安全,调用效率高,不能延时加载)

饿汉式

class Singleton{
    //饿汉式,类加载的时候就进行初始化,避免了线程的同步问题
	private static final Singleton singleton = new Singleton();
	private Singleton() {} //只能在当前类访问它,不能被继承,不能被其他程序用new创建实例对象
    public static Singleton getSingleTon(){
        return singleton;
    }
}

优点:写法简单

缺点:如果从未使用过这个实例,则会造成内存的浪费,也没有达到延迟加载的效果

懒汉式

class Singleton{
	private static Singleton singleton;
	private Singleton() {} //将构造器 私有化,防止外部调用    
	//懒汉式,在第一次调用的时候,即getInstance()方法才进行初始化
	public synchronized static Singleton getInstance() {
		if (singleton ==null) {   //如果为空,创建本实例
			singleton\=new Singleton();
		}
		return singleton;
	}
}

优点:起到了延迟加载的效果,但只能在单线程下使用

缺点:如果在多线程下,一个线程进入了if (singleton == null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。所以 在多线程环境下不可使用这种方式;

懒汉式-双重检查锁式

在双重检查锁中,代码会检查两次单例类是否有已存在的实例

一次加锁,一次不加锁,一次确保不会有多个实例被创建

class Singleton{
	//为了解决访问的是一个初始化未完成的对象,用volatile关键字修饰
    //使用了关键字后,重排序被禁止,所有的写操作都将发生在读操作之前
	private volatile static Singleton singleton;
	private Singleton() {}
	public static Singleton getInstance() {
        if (null == singleton) {  //先判断对象是否已经被初始化,再决定要不要加锁
		synchronized (Singleton.class) {
			if (null == singleton) {
				singleton =new Singleton();
			}
		}
       }
       return singleton;
	}
}

优点:在浪费性能的情况下,解决了在多线程的情况下,这样写可能会导致singleton有多个实例

静态内部类式

//懒汉式:静态内部类形式
public class SingleTon {
    private SingleTon(){}
    private static class Inner{
        private static final SingleTon SINGLE_TON = new SingleTon();
    }
    
    public static SingleTon getSingleTon(){
        return Inner.SINGLE_TON;
    }
}

优点:避免了线程不安全,利用静态内部类特点实现延迟加载,效率高

缺点:在类进行初始化时,别的线程是无法进入的

枚举单例

借助JDK1.5中添加的枚举来实现单例模式

/*
* 枚举类型:表示该类型的对象是有限的几个
* 我们可以限定为一个,就成了单例
*/
public enum SingleTon {
    INSTANCE;
}

优点:不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象

posted @ 2022-07-15 09:29  克峰同学  阅读(31)  评论(0编辑  收藏  举报