1.设计模式的分类
总体来说设计模式分为三大类:
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
往期回顾: 【Java】设计模式(1)—工厂模式
这次我们聊聊单例模式。
什么是单例模式呢,单例模式(Singleton)又叫单态模式,它出现目的是为了保证一个类在系统中只有一个实例,并提供一个访问它的全局访问点。从这点可以看出,单例模式的出现是为了可以保证系统中一个类只有一个实例而且该实例又易于外界访问,从而方便对实例个数的控制并节约系统资源而出现的解决方案。
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
2.饿汉式(立即加载)
/**
* 单例模式-饿汉式
* @author xingyanan01-lhq
*/
public class SingletonEH {
// 将自身实例化对象设置为一个属性,用 static、final修饰,保证SingletonEH被加载时会new出来一个静态不可修改的instance
private static final SingletonEH instance = new SingletonEH();
private SingletonEH (){};
public static SingletonEH getInstance() {
System.out.println("instance:"+instance);
System.out.println("加载饿汉式....");
return instance;
}
public void dealData() {
System.out.println("饿汉式业务处理。");
}
}
/**
* 客户端执行
* @author xingyanan01-lhq
*/
public static void main(String[] args) {
//饿汉式获取唯一的instance
SingletonEH instance = SingletonEH.getInstance();
instance.dealData();
}
饿汉就是SingletonEH 这个类一加载,instance 这个类就也会被加载出来。
“饿汉模式”的优缺点:
优点:实现起来简单,没有多线程同步问题。
缺点:当类SingletonTest被加载的时候,会初始化static的instance,静态变量被创建并分配内存空间,从这以后,这个static的instance对象便一直占着这段内存(即便你还没有用到这个实例),当类被卸载时,静态变量被摧毁,并释放所占有的内存,因此在某些特定条件下会耗费内存。
3.懒汉式(延迟加载)— 线程不安全
/**
* 单例模式-懒汉式
* @author xingyanan01-lhq
*/
public class SingletonLH {
private static SingletonLH instance ;
private SingletonLH (){};
public static SingletonLH getInstance() {
if(instance==null) {
instance = new SingletonLH();
System.out.println("加载懒汉式....");
}
System.out.println("instance:"+instance);
return instance;
}
public void dealData() {
System.out.println("懒汉式业务处理。");
}
}
/**
* 客户端执行
* @author xingyanan01-lhq
*/
public static void main(String[] args) {
//懒汉式获取唯一的instance
SingletonLH instance = SingletonLH.getInstance();
instance.dealData();
instance = SingletonLH.getInstance();
}
“懒汉模式”的优缺点:
优点:实现起来比较简单,当类SingletonTest被加载的时候,静态变量static的instance未被创建并分配内存空间,当getInstance方法第一次被调用时,初始化instance变量,并分配内存,因此在某些特定条件下会节约了内存。
缺点:在多线程环境中,这种实现方法是完全错误的,根本不能保证单例的状态。如果两个线程同时调用就会出现new出两个instance的情况。
4.懒汉式(延迟加载)— 线程安全
/**
* 单例模式-懒汉式(线程安全)
* @author xingyanan01-lhq
*/
public class SingletonLHAQ {
private static SingletonLHAQ instance ;
private SingletonLHAQ (){};
public static synchronized SingletonLHAQ getInstance() {
if(instance==null) {
instance = new SingletonLHAQ();
System.out.println("加载懒汉式....");
}
System.out.println("instance:"+instance);
return instance;
}
public void dealData() {
System.out.println("懒汉式业务处理。");
}
}
其实就是给获取实体类方法加一把synchronized锁。
一个线程用了这个方法,还没走完的情况下,下一个线程就得在外面排队。
“加锁懒汉模式”的优缺点:
优点:在多线程情形下,保证了“懒汉模式”的线程安全。
缺点:众所周知在多线程情形下,synchronized方法通常效率低,显然这不是最佳的实现方案。
5.懒汉式(延迟加载)— DCL双检查锁机制 线程安全
/**
* 单例模式-懒汉式(线程安全)
* @author xingyanan01-lhq
*/
public class SingletonLHsynchronized {
private static SingletonLHsynchronized instance ;
private SingletonLHsynchronized (){};
//我们不对方法上锁
public static SingletonLHsynchronized getInstance() {
//1.当发现instance未被加载时
if(instance==null) {
//2.锁住整个SingletonLHsynchronized类
synchronized(SingletonLHsynchronized.class) {
//3.然后再检查一遍instance,若依然未被加载,则加载instance
//这样从1到2期间不会有其它线程对类进行操作加载
if(instance==null) {
instance = new SingletonLHsynchronized();
System.out.println("加载懒汉式....");
}
}
}
System.out.println("instance:"+instance);
return instance;
}
public void dealData() {
System.out.println("懒汉式业务处理。");
}
}
这是目前单例模式的最佳实现方式。内存占用率高,效率高,线程安全,多线程操作原子性。