资讯专栏INFORMATION COLUMN

Java 设计模式 单例模式

wall2flower / 381人阅读

摘要:单例类如果一个类始终只能创建一个实例,则这个类被称为单例类在一些特殊场景下,要求不允许自由创建该类的对象,而只允许为该类创建一个对象。

单例(Singleton)类

如果一个类始终只能创建一个实例,则这个类被称为单例类

在一些特殊场景下,要求不允许自由创建该类的对象,而只允许为该类创建一个对象。为了避免其他类自由创建该类的实例,应该把该类的构造器使用private修饰,从而把该类的所有构造器隐藏起来

根据良好封装的原则:一旦把该类的构造器隐藏起来,就需要一个public方法作为该类的访问点,用于创建该类的对象,且该方法必须使用static修饰(因为调用该方法之前还不存在对象,因此调用该方法的不可能是对象,只能是类)

除此之外,该类还必须缓存已经创建的对象,否则该类无法知道是否曾经创建过对象,也就无法保证只创建了一个对象。为此该类需要使用一个成员变量来保存曾经创建的对象,因为该成员变量需要被上面的静态方法访问,故该成员变量必须使用static修饰

class Singleton
{
    // 使用一个类变量来缓存曾经创建的实例
    private static Singleton instance;
    // 将构造器使用private修饰,隐藏该构造器
    private Singleton(){}
    // 提供一个静态方法,用于返回Singleton实例
    // 该方法可以加入自定义的控制,保证只产生一个Singleton对象
    public static Singleton getInstance()
    {
        // 如果instance为null,表明还不曾创建Singleton对象
        // 如果instance不为null,则表明已经创建了Singleton对象,
        // 将不会重新创建新的实例
        if (instance == null)
        {
            // 创建一个Singleton对象,并将其缓存起来
            instance = new Singleton();
        }
        return instance;
    }
}
public class SingletonTest
{
    public static void main(String[] args)
    {
        // 创建Singleton对象不能通过构造器,
        // 只能通过getInstance方法来得到实例
        Singleton s1 = Singleton.getInstance();
        Singleton s2 = Singleton.getInstance();
        System.out.println(s1 == s2); // 将输出true
    }
}
Coding

代码一:

public class Singleton {  
    private Singleton() {}                     // 关键点0:构造函数是私有的
    private static Singleton single = null;    // 关键点1:声明单例对象是静态的
    public static Singleton GetInstance()      // 通过静态方法来构造对象
    {                        
         if (single == null)
         {                                     // 关键点2:判断单例对象是否已经被构造
             single = new Singleton();  
         }    
        return single;  
    }  
}

代码一是线程不安全的,遇到多线程的并发条件下,有可能给new出多个单例实例

========================================================================================

代码二:

public class Singleton {  
    private Singleton() {}                     // 关键点0:构造函数是私有的
    private static Singleton single = null;    // 关键点1:声明单例对象是静态的
    private static Object obj= new Object();
    public static Singleton GetInstance()      // 通过静态方法来构造对象
    {                        
         if (single == null)                   // 关键点2:判断单例对象是否已经被构造
         {                            
            lock(obj)                          // 关键点3:加线程锁
            {
               single = new Singleton();  
             }
         }    
        return single;  
    }  
}

在关键点2,检测单例是否被构造。虽然这里判断了一次,但是由于某些情况下,可能有延迟加载或者缓存的原因,只有关键点2这一次判断,仍然不能保证系统是否只创建了一个单例,也可能出现多个实例的情况

========================================================================================

代码三:

public class Singleton {  
    private Singleton() {}                     // 关键点0:构造函数是私有的
    private static Singleton single = null;    // 关键点1:声明单例对象是静态的
    private static object obj= new object();
    public static Singleton GetInstance()      // 通过静态方法来构造对象
    {                        
         if (single == null)                   // 关键点2:判断单例对象是否已经被构造
         {                            
            lock(obj)                          // 关键点3:加线程锁
            {
               if(single == null)              // 关键点4:二次判断单例是否已经被构造
               {
                  single = new Singleton();  
                }
             }
         }    
        return single;  
    }  
}

在判断单例实例是否被构造时,需要检测两次,在线程锁之前判断一次,在线程锁之后判断一次,再去构造实例

单例模式关键点

单例是为了保证系统中只有一个实例,其关键点有:

私有构造函数

声明静态单例对象

构造单例对象之前要加锁(lock一个静态的object对象)

需要两次检测单例实例是否已经被构造,分别在锁之前和锁之后

单例模式问答 为何要检测两次?

如上面所述,有可能延迟加载或者缓存原因,造成构造多个实例,违反了单例的初衷

构造函数能否公有化?

不行,单例类的构造函数必须私有化,单例类不能被实例化,单例实例只能静态调用

lock住的对象为什么要是object对象,可以是int吗?

不行,锁住的必须是个引用类型。如果锁值类型,每个不同的线程在声明的时候值类型变量的地址都不一样,那么上个线程锁住的东西下个线程进来会认为根本没锁,相当于每次都锁了不同的门。引用类型的变量地址是相同的,每个线程进来判断锁都想是否被锁的时候都是判断同一个地址,相当于是锁在通一扇门,起到了锁的作用

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/66498.html

相关文章

  • 单例模式你会几种写法?

    摘要:使用静态类体现的是基于对象,而使用单例设计模式体现的是面向对象。二编写单例模式的代码编写单例模式的代码其实很简单,就分了三步将构造函数私有化在类的内部创建实例提供获取唯一实例的方法饿汉式根据上面的步骤,我们就可以轻松完成创建单例对象了。 前言 只有光头才能变强 回顾前面: 给女朋友讲解什么是代理模式 包装模式就是这么简单啦 本来打算没那么快更新的,这阵子在刷Spring的书籍。在看...

    solocoder 评论0 收藏0
  • 设计模式单例模式

    摘要:单例模式关注的重点私有构造器线程安全延迟加载序列化和反序列化安全反射攻击安全相关设计模式单例模式和工厂模式工厂类可以设计成单例模式。 0x01.定义与类型 定义:保证一个类仅有一个实例,并提供一个全局访问点 类型:创建型 UML showImg(https://segmentfault.com/img/bVbtDJ2?w=402&h=268); 单例模式的基本要素 私有的构造方...

    陆斌 评论0 收藏0
  • Java设计模式-单例模式(Singleton Pattern)

    摘要:如果需要防范这种攻击,请修改构造函数,使其在被要求创建第二个实例时抛出异常。单例模式与单一职责原则有冲突。源码地址参考文献设计模式之禅 定义 单例模式是一个比较简单的模式,其定义如下: 保证一个类仅有一个实例,并提供一个访问它的全局访问点。 或者 Ensure a class has only one instance, and provide a global point of ac...

    k00baa 评论0 收藏0
  • 深入理解单例模式

    摘要:总结我们主要介绍到了以下几种方式实现单例模式饿汉方式线程安全懒汉式非线程安全和关键字线程安全版本懒汉式双重检查加锁版本枚举方式参考设计模式中文版第二版设计模式深入理解单例模式我是一个以架构师为年之内目标的小小白。 初遇设计模式在上个寒假,当时把每个设计模式过了一遍,对设计模式有了一个最初级的了解。这个学期借了几本设计模式的书籍看,听了老师的设计模式课,对设计模式算是有个更进一步的认识。...

    FuisonDesign 评论0 收藏0
  • Java基础学习——多线程之单例设计模式(转)

    摘要:总之,选择单例模式就是为了避免不一致状态,避免政出多头。二饿汉式单例饿汉式单例类在类初始化时,已经自行实例化静态工厂方法饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的。 概念:  Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍两种:懒汉式单例、饿汉式单例。  单例模式有以下特点:  1、单例类只能有一个实例。 ...

    dendoink 评论0 收藏0
  • 从未这么明白的设计模式(一):单例模式

    摘要:一般来说,这种单例实现有两种思路,私有构造器,枚举。而这种方式又分了饱汉式,饿汉式。通过关键字防止指令重排序。什么是单例?为什么要用单例? 一个类被设计出来,就代表它表示具有某种行为(方法),属性(成员变量),而一般情况下,当我们想使用这个类时,会使用new关键字,这时候jvm会帮我们构造一个该类的实例。而我们知道,对于new这个关键字以及该实例,相对而言是比较耗费资源的。所以如果我们能够想...

    NikoManiac 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<