单例模式
单例模式,顾名思义,在程序运行中,实例化某个类时只实例化一次,即只有一个实例对象存在。例如在古代,一个国家只能有一个皇帝,在现代则是主席或总统等。
在Java语言中单例模式有以下实现方式
1.饿汉式
importorg.junit.jupiter.api.Test;public classSingleton {//静态成员变量
private static Singleton singleton = newSingleton();privateString name;publicString getName() {returnname;
}public voidsetName(String name) {this.name =name;
}//构造函数私有化
privateSingleton(){
}//返回静态资源中Singleton实例
public staticSingleton getInstance() {returnsingleton;
}/*** 单元测试*/@Testpublic voidtestSingleton() {//通过调用类的静态方法返回类的实例对象
Singleton s1 =Singleton.getInstance();
Singleton s2=Singleton.getInstance();
s1.setName("zhangsan");
s2.setName("lisi");
System.out.println(s1.getName());
System.out.println(s2.getName());
}
}
在类加载时,直接将实例对象初始化,并且该实例是静态的,属于类的成员变量,通过调用类的静态方法返回该对象。
运行testSingleton单元测试,输出的两行都是lisi,因为s1,s2指向的同一个实例对象,这个对象在类创建的时候就存在了。
饿汉式是线程安全的,不管系统的那一个线程获取这个对象,他们都是该类同一个对象。缺点是在程序在一开始就创建了该对象,占用内存空间。下面这种实现方式增加判断,在程序调用时才实例化该对象。
2.懒汉式
importorg.junit.jupiter.api.Test;public classSingleton {//不初始化实例对象
private static Singleton singleton = null;privateString name;publicString getName() {returnname;
}//构造函数私有化
privateSingleton(){
}public voidsetName(String name) {this.name =name;
}//当被调用时才动态实例化
public staticSingleton getInstance() {if(singleton == null) {
singleton= newSingleton();
}returnsingleton;
}
}
懒汉式解决了饿汉式的实例对象初始化占用内存的情况,但是懒汉式存在线程安全的问题,当多个线程同时访问getInstance()方法时,有可能在第一个线程进入if语句是还没new Singleton()时,这时第二个线程判断if的时候就会为真,则会创建新的实例,单例模式设计失败。
这时需要在getInstance()方法上添加synchronized修饰符,表示线程同步,即当一个线程访问该方法时,其他线程需要等待其释放资源。
public static synchronizedSingleton getInstance() {if(singleton == null) {
singleton= newSingleton();
}returnsingleton;
}
这样解决了懒汉式的线程不安全的问题,但是这样会降低系统的性能,当一个线程占用了该资源,其他的线程只能等待,系统的性能大大下降。于是乎第三种实现模式,对懒汉式进行了改进。
3.双重检测
public staticSingleton getInstance() {if(singleton == null) {synchronized (Singleton.class) {if(singleton==null) {
singleton= newSingleton();
}
}
}returnsingleton;
}
双重检测,线程访问时有两次检测。
这里将synchronized放到判断语句里面,这样当第一个线程调用getInstance()方法时,singleton为空,进入synchronized代码块,其他的线程即使也判断singleton为空,则需要等待第一个线程完成资源的使用,这样保证了线程的安全。
当实例化对象完成时,其他的线程调用getInstance()方法时,直接返回Singleton对象即可,不用再等待,这一点优化了系统,提高了系统的性能。
4.总结
模式来源于生活。本文用Java语言实现了单例模式。三种实现方式都是线程安全的,饿汉式比较占用内存空间;懒汉式则降低了系统的性能;双重检测是懒汉式的升级,即能保证线程的安全,也能以懒加载的方式实现单例模式,在大规模系统中节省对象的创建时间,提高系统的性能。在系统中共享同一个资源或同一个对象,则可利用单例模式来实现。