创建型模式--单例模式(Singleton)

本文详细介绍了单例模式的概念、两种实现方式(饿汉式和懒汉式),并探讨了它们的特点及适用场景。通过对比分析,帮助读者理解如何选择合适的单例模式实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 Singleton:Ensure a class only has one instance, and provide a global point of access to it.

一个类只能有一个实例的创建模式。

一:引入

 在某些情况下一个类只能有一个实例,如果多于一个实例就会导致逻辑错误。

  • 非共享资源:如打印机,系统属性文件
  • 其他:如数据库主键生成器,只能有一个地方分配,否则会出现重复主键
  1. EagerSingleton(饿汉式单例):  
/**
 * 饿汉式单例
 
*/

public   class  EagerSingleton  {
    
//类加载时实例化
    private  static final EagerSingleton instance=new EagerSingleton();
    
//构造函数设为私有,不能以new的方式生成新的实例
    private EagerSingleton()
    
{        
    }

    
//提供给客户的得到唯一实例的方法
    public static EagerSingleton getInstance()
    
{
         
return instance;
    }

}
 

 

public   class  Client  {
      
public static void main(String args[])
      
{
          EagerSingleton s1 
= EagerSingleton.getInstance();
          EagerSingleton s2 
= EagerSingleton.getInstance();

        
if( s1 == s2 )
          System.out.println( 
"s1 == s2" );
      }

}

问题:

  • 类在加载时就将自己实例化,对于象资源控制器之类的类初始化可能耗费很多时间。还可能会导致出现多线程首次同时引用子类的几率变得比较大。
  • 构造函数为私有,不能被继承。
  1. LazySingleton(懒汉式单例)--延迟加载(访问时加载)
/**
 * 懒汉式单例
 
*/

public   class  LazySingleton  {
    
//类加载时为null,不实例化
    private  static  LazySingleton instance=null;
    
//构造函数设为私有,不能以new的方式生成新的实例
    private LazySingleton()
    
{        
    }

    
//提供给客户的得到唯一实例的方法
    public static LazySingleton getInstance()
    
{
        
//如果没有创建实例就创建,否则就用以前创建了的那个。
        if (instance==null) instance=new LazySingleton();
         
return instance;
    }

}
  • 第一次访问时实例化,资源利用效率比饿汉式要好,但第一次访问时反应时间不如饿汉式。
  • 因为构造函数私有,也不能被继承。

上例没有考虑到多线程环境,如果第一个线程执行到 if(instance==null)且还没有执行instance=new LazySingleton()时,另一个线程也执行到 if(instance==null)这时条件也为true,所以也会执行new LazySingleton()导致多实例。

 

// 整个方法都加锁,防止多线程环境下的问题
     synchronized   public   static  LazySingleton getInstance()
    
{
        
//如果没有创建实例就创建,否则就用以前创建了的那个。
        if (instance==null) instance=new LazySingleton();
         
return instance;
    }

 

/**
 * 懒汉式单例,多线程环境
 
*/

public   class  LazySingleton  {
    
// 类加载时为null,不实例化.
    
// volatile ensures that multiple threads handle the instance variable
    
// correctly
    
// when it is being initialized to the Singleton instance.
    private volatile static LazySingleton instance = null;

    
// 构造函数设为私有,不能以new的方式生成新的实例
    private LazySingleton() {
    }


    
// 两阶段加锁,防止多线程环境下的问题,效率比整个方法加锁高。
    public static LazySingleton getInstance() {
        
// 如果没有创建实例就创建,否则就用以前创建了的那个。
        if (instance == null{
            
synchronized (LazySingleton.class{
                
if (instance == null{
                    instance 
= new LazySingleton();
                }

            }

        }

        
return instance;
    }

}

 

二:结构

    

三:实际应用

  1. java.lang.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() {}
}

 

 

四:适用情形

Use the Singleton pattern when

  • there must be exactly one instance of a class, and it must be accessible to clients from a well-known access point.

     

  • when the sole instance should be extensible by subclassing, and clients should be able to use an extended instance without modifying

参考文献:
1:阎宏,《Java与模式》,电子工业出版社
2:Eric Freeman & Elisabeth Freeman,《Head First Design Pattern》,O'REILLY

  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值