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