热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Java单例模式详解(图文并茂,简单易懂)(适配器、单例、静态代理、简单工厂设计模式)https://www.cnblogs.com/cmusketeer/p/8146510.html

PS:首先我们要先知道什么是单例,为什么要用单例,用的好处是什么等问题来看。1:java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍两种:懒汉式单例、饿

PS:首先我们要先知道什么是单例,为什么要用单例,用的好处是什么等问题来看。

1:java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍两种:懒汉式单例、饿汉式单例

单例模式有以下特点:  

  1、单例类只能有一个实例。
  2、单例类必须自己创建自己的唯一实例。
  3、单例类必须给所有其他对象提供这一实例。

目的

  单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具有资源管理器的功能。每台计算机可以有若干个打印机,但只能有一个Printer Spooler,以避免两个打印作业同时输出到打印机中。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。总之,选择单例模式就是为了避免不一致状态,避免政出多头。

2:懒汉式

先把单例类写出来

public class SingletonTest {
    //懒汉式单例类.在第一次调用的时候实例化自己 
    private SingletonTest() {}
        private static SingletonTest single=null;
        //静态工厂方法 
        public static SingletonTest getInstance() {
             if (single == null) {  
                 single = new SingletonTest();
                 System.out.println("创建一次");
             }  
            return single;
        }
        
        public void show(){
            System.out.println("我是show");
        }

}

这里直接上代码,代码中有详解

public class SingletonTest2 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //故意写获取两次,创建两个对象
        SingletonTest singleton=SingletonTest.getInstance();
        SingletonTest singleton2=SingletonTest.getInstance();
        
        //Singleton对象只创建一次,但是写两次还是可以的,而且方法都是可以调用的,但是看下面
        singleton.show();
        singleton2.show();
        
        //两个对象的表现形式一样
        if(singleton == singleton2){
            System.out.println("该对象的字符串表示形式:");
            System.out.println("singleton :"+singleton.toString());
            System.out.println("singleton2:"+singleton2.toString());
        }
}

 


 

由上面的图可以看出就算多创建几个对象,在底部也是只有一个singleton对象实例,而且创建出来的对象的字符串表现形式也是一样的,有的人肯定有疑问,那平常两个对象是什么样子的呢,我下面给你解释说明,在这之前我写说一下这个懒汉式需要注意的地方,它是线程不安全的,并发环境下很可能出现多个Singleton实例,有很多方法可以解决,比如说同步锁,静态内部类等,这里主要说静态内部类,这个比较好点,

 

public class Singleton3 {  
    private static class SingletonHolder {  
       private static final Singleton3 INSTANCE = new Singleton3();  
    }  
    private Singleton3 (){}  
    public static final Singleton3 getInstance() {  
        System.out.println("singleton创建");
       return SingletonHolder.INSTANCE;  
    }  
}

 

调用:

 

Singleton3 singleton3=Singleton3.getInstance();
        Singleton3 singleton4=Singleton3.getInstance();
        if(singleton3 == singleton4){
            System.out.println("该对象的字符串表示形式:");
            System.out.println("singleton3:"+singleton3.toString());
            System.out.println("singleton4:"+singleton4.toString());
        }

 


结果图:

 

这里我也是创建了两个对象来说明,神奇的是打印了两次singleton创建,这难道是又创建成功了的对象吗?答案是:虽然打印了两次,对象名也有两个,但是该对象的字符串表示形式还是一样的,而且大家都知道static的用法,就是在类被加载的同时该singleton对象就已经被创建,后期不会再被创建,就算后期自己又调用了getInstance()方法,但底层还是公用的一个Singleton对象.

同样,我写了一个普通的类,来同时创建两个对象,并且打印他们的toString()方法,如下:

 

     QuBie qb1=new QuBie();
        QuBie qb2=new QuBie();
        if(qb1 == qb2){
            System.out.println("该对象的字符串表示形式:");
            System.out.println("singleton3:"+qb1.toString());
            System.out.println("singleton4:"+qb2.toString());
        }else{
            System.out.println("该对象的字符串表示形式:");
            System.out.println("singleton3:"+qb1.toString());
            System.out.println("singleton4:"+qb2.toString());
        }

 



 

由此可看出来对象的字符串表示形式是不一样的

3:饿汉式单例

饿汉式单例类.在类初始化时,已经自行实例化

public class Singleton1 {
  private Singleton1() {}
  private static final Singleton1 single = new Singleton1();
  //静态工厂方法 
  public static Singleton1 getInstance() {
      return single;
  }
}


因为这本身就是static修饰的方法,所以是在类加载的时候被创建,后期不会再改变,所以线程是安全的。

4:双检锁/双重校验锁

描述:采用双锁机制,安全且在多线程情况下能保持高性能。多线程安全

 

public class Singleton {  
    private volatile static Singleton singleton;  
    private Singleton (){}  
    public static Singleton getSingleton() {  
    if (singleton == null) {  
        synchronized (Singleton.class) {  
        if (singleton == null) {  
            singleton = new Singleton();  
        }  
        }  
    }  
    return singleton;  
    }  
}

这里的两次判断,第一判断:效率,第二判断:避免同步。之所以这样是因为避免加锁后,再次加锁。大大增强了执行效率。

 




推荐阅读
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 本文介绍了Java高并发程序设计中线程安全的概念与synchronized关键字的使用。通过一个计数器的例子,演示了多线程同时对变量进行累加操作时可能出现的问题。最终值会小于预期的原因是因为两个线程同时对变量进行写入时,其中一个线程的结果会覆盖另一个线程的结果。为了解决这个问题,可以使用synchronized关键字来保证线程安全。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • JVM 学习总结(三)——对象存活判定算法的两种实现
    本文介绍了垃圾收集器在回收堆内存前确定对象存活的两种算法:引用计数算法和可达性分析算法。引用计数算法通过计数器判定对象是否存活,虽然简单高效,但无法解决循环引用的问题;可达性分析算法通过判断对象是否可达来确定存活对象,是主流的Java虚拟机内存管理算法。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • 本文介绍了Swing组件的用法,重点讲解了图标接口的定义和创建方法。图标接口用来将图标与各种组件相关联,可以是简单的绘画或使用磁盘上的GIF格式图像。文章详细介绍了图标接口的属性和绘制方法,并给出了一个菱形图标的实现示例。该示例可以配置图标的尺寸、颜色和填充状态。 ... [详细]
  • 本文介绍了Java中Hashtable的clear()方法,该方法用于清除和移除指定Hashtable中的所有键。通过示例程序演示了clear()方法的使用。 ... [详细]
  • 重入锁(ReentrantLock)学习及实现原理
    本文介绍了重入锁(ReentrantLock)的学习及实现原理。在学习synchronized的基础上,重入锁提供了更多的灵活性和功能。文章详细介绍了重入锁的特性、使用方法和实现原理,并提供了类图和测试代码供读者参考。重入锁支持重入和公平与非公平两种实现方式,通过对比和分析,读者可以更好地理解和应用重入锁。 ... [详细]
  • 使用eclipse创建一个Java项目的步骤
    本文介绍了使用eclipse创建一个Java项目的步骤,包括启动eclipse、选择New Project命令、在对话框中输入项目名称等。同时还介绍了Java Settings对话框中的一些选项,以及如何修改Java程序的输出目录。 ... [详细]
author-avatar
shirliyap
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有