zoukankan      html  css  js  c++  java
  • 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;  
        }  
    }

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

    (适配器、单例、静态代理、简单工厂设计模式)https://www.cnblogs.com/cmusketeer/p/8146510.html



  • 相关阅读:
    iOS实现微信外部H5支付完成后返回原APP(多APP也可实现)
    微信开发,仿原生实现 “再按一次返回”功能
    centos 环境变量配置
    centos 6.* 配置端口
    linux 中 svn 服务器搭建 重启
    删除apache注册表
    Linux 编译安装 php 扩展包 curl
    手机APP中使用history.back()返回没有效果的解决
    Centos 6.5升级安装Git
    linux 已有目录挂载磁盘
  • 原文地址:https://www.cnblogs.com/cmusketeer/p/8016550.html
Copyright © 2011-2022 走看看