欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java技术---单件/单例模式

程序员文章站 2024-03-12 11:38:32
...

1.确保一个类只有一个实例,自行实例化并向系统提供这个实例

(1)整个系统只需要拥有一个的全局对象,这样有利于协调系统整体的行为
(2)返回对象一个引用(永远是同一个)和一个获得该实例的方法(必须是静态方法,通常使用getInstance())
(3)将该类的构造函数定义为私有方法
(4) 所谓单例,指的就是单实例,有且仅有一个类实例,这个单例不应该由人来控制,而应该由代码来限制,强制单例
(5)单例模式应用实例:
    <1>网站的计数器,一般采用单例模式实现,否则难以同步
    <2>应用程序的日志应用,一般都用单例模式实现
    <3>Web应用的配置对象的读取,一般也应用单例模式,这个是由于配置文件是共享的资源
    <4>数据库连接池的设计/多线程的线程池的设计
    <5> 操作系统的文件系统,也是大的单例模式实现的具体例子,一个操作系统只能有一个文件系统
    <6>HttpApplication 也是单位例的典型应用

2.单例模式分类:饿汉式,懒汉式,双重检测 ,静态内部类

1)饿汉式单例模式:
      <1>类加载时实例化一个对象给自己的引用
      <2>单例实例在类装载时就构建,并保存在类中。(预先加载法)
      <3>优点:线程安全;
               在类加载的同时已经创建好一个静态对象,调用时反应速度快 ;
       <4>缺点:资源效率不高,可能getInstance()永远不会执行到,
                但执行该类的其他静态方法或者加载了该类(class.forName),那么这个实例仍然初始化  
            //饿汉式(推荐)
           public class EHanDanli{
             //定义私有的无参构造器,用于单例实例
             private EHanDanli() {}
            //此处定义类变量实例并直接实例化,在类加载的时候就完成了实例化并保存在类中
             public static EHanDanli eh= new EHanDanli();
             //定义公开方法,返回已创建的单例
             public EHanDanli getInstance() {
                 return eh;
             } }2)懒汉式单例模式:线程不安全
       <1>单例实例在第一次被使用时再构建,延迟初始化
       <2>优点:避免了饿汉式的那种在没有用到的情况下创建事例;
                资源利用率高,不执行getInstance()就不会被实例,可以执行该类的其他静态方法
       <3>缺点:在多个线程同事访问的时候就可能同事创建多个实例,而且这多个实例不是同一个对象,
                虽然后面创建的实例会覆盖先创建的实例,但是还是会存在拿到不同对象的情况。
                解决这个问题的办法就是加锁synchonized,第一次加载时不够快,多线程使用不必要的同步开销大  
                会降低性能,同步一个方法可能造成程序执行效率下降100倍。       
           public class LHanDanli {
          //定义私有类变量来存放单例,私有的目的是指外部无法直接获取这个变量,而要使用提供的公共方法来获取
          private static LHanDanli lh = null;
          //定义私有构造器,表示只在类内部使用,亦指单例的实例只能在单例类内部创建
          private LHanDanli(){}
         /**
           * 定义公开的方法来返回该类的实例,需要在第一次使用时生成实例,
           *多个线程判断lh都为null时,在执行new操作时多线程会出现重复情况
           *所以为了线程安全,使用synchronized关键字来确保只会生成单例
          **/
           public static synchronized LHanDanli getInstance(){
              if(lh == null){
               lh = new LHanDanli();}
                  return lh;}3)双重检测 
      <1> 使用双重加锁,保证getInstacne()只在第一次会使用同步    
      <2>优点:资源利用率高,不执行getInstance()就不被实例,可以执行该类其他静态方法 
              volatile关键字确保当变量被初始化成Singleton实例时,多个线程正确的处理变量   
              volatile保证了共享变量的可见性,一个线程对变量的操作其他线程会立马知晓,
              不会出现还未初始化完成就被使用的情况 
      <3>缺点:第一次加载时反应不快,由于java内存模型一些原因偶尔失败 
               Java1.4中JVM虚拟机对于volatile关键字的实现会导致双重检查加锁失败,只能使用Java5或以上的版本
           public class Singleton {
             private volatile static Singleton uniqueInstance;
             private Singleton () {}
             public static Singleton getInstance() {
                if (uniqueInstacne == null) {
                      synchronized (Singleton.class) {
                          if (uniqueInstance == null) {
                               uniqueInstance = new Singleton();
                               }}}
                                 return uniqueInstance; }}4)静态内部类 
      <1>优点:资源利用率高,不执行getInstance()不被实例,可以执行该类其他静态方法
      <2>缺点:第一次加载时反应不够快                                  
           public class Test {
               private Test() {}
               private static class SingletonHelp {
                  static Test instance = new Test();}
               public static Test getInstance() {
                 return SingletonHelp.instance;}}                                       

3.总结:

(1)一般采用饿汉式:java中饿汉式性能优于懒汉式,c++中一般使用懒单例模式
(2)若对资源十分在意可以采用静态内部类,不建议采用懒汉式及双重检测
(3)单件模式中多线程情况下重复创建对象问题的处理办法:一般采用双重检测 
(4)单例模式必须具备的3个元素:
    <1>私有静态属性,用于存取类的唯一实例
    <2>公共静态方法,用于提供对该唯一实例的存取访问,如果实例未创建,则创建该实例
    <3>用于限制类再次实例化的方式。通常使用私有构建函数的方式来实现
相关标签: java技术基础专栏