zoukankan      html  css  js  c++  java
  • 单例模式

    单例模式

    单例模式就是针对一个类创建唯一一个对象,并且提供一个可供全局范围内能够访问该对象的方法。貌似有点晦涩难弄……,举个例子,例如在一个地铁站里面,一般有且只有一个厕所,但是这个厕所的们又是敞开着的,旅客们在需要的时候都可以用这个厕所。OK,那么在上述的例子中,地铁站就是我们要开发的程序,而厕所作为一个概念是一个类的名称,而地铁站里面的这个唯一具体的厕所就是程序中唯一的一个创建对象,厕所的门相当于是程序中提供给其他程序访问这个对象的方法。不知道我说明白了没有……如果不明白的话看看下面的代码吧/kb

    单例模式分为三种类型,分别是饿汉式,懒汉式,双重检查。

    下面我们以造小人为例,来分别介绍这三种类型的实现

    (1)  饿汉式

    首先定义Person类

    Person.java

    package asingleton01;

     

    public class Person {

        public static final Person personnew Person();

        private String name = null;

       

       

        public String getName() {

           return name;

        }

     

        public void setName(String name) {

           this.name = name;

        }

     

        //构造方法私有化

        private Person(){}

        //提供一个全局的静态方法

        public static Person getPerson(){

           return person;

        }

    }

    我们主要来分析这个Person.java,在代码的开始,我们就定义了这么一条语句

     

    public static final Person personnew Person();

    这是非常关键的一句,首先我们使用了static来修饰person,是为了保证person的全局唯一性,另外使用final是为了person有且只能在声明的时候被赋值。

    有了这么一条语句,我们就可以放心person在整个程序的运行中,有且只有一个对象了。当然创造了这唯一的一个person对象后,我们还需要提供一个方法,供其他的类来引用person对象,于是便有了下面这条语句

    //提供一个全局的静态方法

        public static Person getPerson(){

           return person;

        }

    然后我们来测试一下:

    package asingleton01;

     

    public class MainClass {

        public static void main(String[] args) {

           Person per1 = Person.getPerson();

           Person per2 = Person.getPerson();

          

           per1.setName("张三");

           per2.setName("李四");

          

           System.out.println(per1.getName());

           System.out.println(per2.getName());

        }

    }

    测试结果:

    李四

    李四

    其实这种单例模式是十分方便有效的,即使在多线程中,也能保证Person实例是有一个,因为在只有Person在被加载的时候才会被初始化。

    (2)  懒汉式

    废话不多少,直接上代码

    package asingleton02;

     

    public class Person {

        private String name = null;

        private static Person person = null;

       

        public String getName() {

           return name;

        }

       

        public void setName(String name) {

           this.name = name;

        }

     

        //构造方法私有化

        private Person(){}

     

        public static synchronized Person getPerson(){

           if(person==null){

               person = new Person();

           }

           return person;

        }

    }

    大家可能很快的发现了,在和饿汉式的Person.java代码相对比中,有两个明显的区别:

    a.

    饿汉式:public static final Person personnew Person();

    懒汉式:private static Person person = null;

    b.

    饿汉式:

    public static Person getPerson(){

           return person;

        }

    懒汉式:

    public static synchronized Person getPerson(){

           if(person==null){

               person = new Person();

           }

           return person;

        }

    通过对比,我们会发现懒汉式把person对象的构建从最初的声明阶段放到了getPerson方法中,但是在这个getPerson方法中,我们添加了synchronized跟if语句,synchronized是为了多线程在创建该方法的时候也只创建一个Person对象实例,而if判断语句则是为了创建唯一的person对象!

    (3)  双重检查

    直接贴Person.java代码

    Person.java

    package asingleton03;

     

    public class Person {

        private String name = null;

        private static Person person = null;

       

        public String getName() {

           return name;

        }

       

        public void setName(String name) {

           this.name = name;

        }

     

        //构造方法私有化

        private Person(){}

       

        public static Person getPerson(){

           if(person==null){

               synchronized(Person.class){

                  if(person==null){

                      person = new Person();

                  }

               }

           }

           return person;

        }

    }

    乍一看感觉双重检查跟懒汉式貌似没有什么区别,但是心细的同学发现了两个种类的getPerson还是稍显不同,为什么双重检查要这样呢?

    我们先考虑一个问题,如果有多个线程同时调用getPerson方法,如果是懒汉式(代码如下)

     

    public static synchronized Person getPerson(){

           if(person==null){

               person = new Person();

           }

           return person;

        }

     

    那么由于synchronized作用于整个方法,那么只能有一个线程调用getPerson方法,其他的线程都得等待。这样的话可能会引起程序的卡顿。

     

    如果我们改成双重检查(代码如下)

     

    public static Person getPerson(){

           if(person==null){

               synchronized(Person.class){

                  if(person==null){

                      person = new Person();

                  }

               }

           }

           return person;

        }

     

    由于synchronized作用于部分代码片段而不是整个方法,所以所有的线程都可以进入getPerson方法,无需等待,所以效率问题解决了。而接下来的synchronized也解决了person对象唯一性的问题。

     

    其实这三种单例模式最为简单实用的还是饿汉式,但是懒汉式跟双重检查因为要考虑到多线程的问题,可以锻炼我们解决问题的思维模式。总之各有千秋吧。

  • 相关阅读:
    周五笔记
    python2.0代码重构为3.0一日记
    小白使用Bert跑分类模型
    andrew ng 深度学习 网易云课堂课程
    andrew ng machine learning week9 异常检测和推荐系统
    解决端口占用问题
    postgresqlmysql删除数据表中字段的回车和换行
    echarts常用的属性修改
    后端返回文件流,用blog方式下载 type 值
    antD vue 遇到的一些问题处理
  • 原文地址:https://www.cnblogs.com/magicy/p/4631798.html
Copyright © 2011-2022 走看看