一、应用杨景

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

二、特点

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

三、懒汉式单例

//懒汉式单例类.在第一次调用的时候实例化自己

public class Singleton {
    private Singleton() {}
    private static Singleton single=null;
    public static Singleton getInstance() {
        if (single == null) {
            single = new Singleton();
        }
        return single;
    }
}

Singleton通过将构造方法限定为private避免了类在外部被实例化,在同一个虚拟机范围内,Singleton的唯一实例只能通过getInstance()方法访问。

但是以上懒汉式单例的实现没有考虑线程安全问题,它是线程不安全的,并发环境下很可能出现多个Singleton实例,要实现线程安全,有以下三种方式,都是对getInstance这个方法改造,保证了懒汉式单例的线程安全。

1、在getInstance方法上加同步

public class Singleton {
    private Singleton() {}
    private static Singleton single=null;
    public static synchronized Singleton getInstance() {
        if (single == null) {
            single = new Singleton();
        }
        return single;
    }
}

2、双重检查锁定

public class Singleton {
    private Singleton() {}
    private static Singleton single=null;
    public static Singleton getInstance() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}
 
3、静态内部类
public class Singleton {
    private static class LazyHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
    private Singleton (){}
    public static final Singleton getInstance() {
        return LazyHolder.INSTANCE;
    }

这3种方法的区别:

第1种,在方法调用上加了同步,虽然线程安全了,但是每次都要同步,会影响性能,毕竟99%的情况下是不需要同步的。

第2种,在getInstance中做了两次null检查,确保了只有第一次调用单例的时候才会做同步,这样也是线程安全的,同时避免了每次都同步的性能损耗。

第3种,利用了classloader的机制来保证初始化instance时只有一个线程,所以也是线程安全的,同时没有性能损耗,建议使用这一种。

四、饿汉式单例

//饿汉式单例类.在类初始化时,已经自行实例化
public class Singleton1 {
    private Singleton1() {}
    private static final Singleton1 single = new Singleton1();
    //静态工厂方法
   
public static Singleton1 getInstance() {
        return single;
    }
}

饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的。

五、饿汉式和懒汉式区别

从名字上来说,饿汉就是类一旦加载,就把单例初始化完成,保证getInstance的时候,单例是已经存在的了;而懒汉比较懒,只有当调用getInstance的时候,才回去初始化这个单例。

另外从以下两点再区分以下这两种方式:

1、线程安全:

饿汉式天生就是线程安全的,可以直接用于多线程而不会出现问题,

懒汉式本身是非线程安全的,为了实现线程安全有几种写法,分别是上面的1、2、3,这三种实现在资源加载和性能方面有些区别。

2、资源加载和性能:

饿汉式在类创建的同时就实例化一个静态对象出来,不管之后会不会使用这个单例,都会占据一定的内存,但是相应的,在第一次调用时速度也会更快,因为其资源已经初始化完成;而懒汉式顾名思义,会延迟加载,在第一次使用该单例的时候才会实例化对象出来,第一次调用时要做初始化,如果要做的工作比较多,性能上会有些延迟,之后就和饿汉式一样了。

六、什么是线程安全?

如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

或者说:一个类或者程序所提供的接口对于线程来说是原子操作,或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题,那就是线程安全的。

七、应用

以下是一个单例类使用的例子,以懒汉式为例,这里为了保证线程安全,使用了双重检查锁定的方式:

class Singleton {
    String name = null;     private Singleton() {
    }     private static volatile Singleton instance = null;     public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }     public String getName() {
        return name;
    }     public void setName(String name) {
        this.name = name;
    }     public void printInfo() {
        System.out.println("the name is " + name);
    }
} public class TestSingleton {
    public static void main(String[] args){
        Singleton ts1 = Singleton.getInstance();
        ts1.setName("Zhang San");
       
        Singleton ts2 = Singleton.getInstance();
        ts2.setName("Li Si");         ts1.printInfo();
        ts2.printInfo();         if(ts1 == ts2){
            System.out.println("创建的是同一个实例");
        }else{
            System.out.println("创建的不是同一个实例");
        }
    }
}

运行结果:

这里可以看出,两次创建的是同一个实例,第一次name值为Zhang San,第二次name值为LiSi。第二次的值覆盖了第一次的值,所以最终name的值为LiSi。

结论:由结果可以得知单例模式为一个面向对象的应用程序提供了对象惟一的访问点,不管它实现何种功能,整个应用程序都会同享一个实例对象。

Java笔记5:单例模式的更多相关文章

  1. effective java笔记之单例模式与序列化

    单例模式:"一个类有且仅有一个实例,并且自行实例化向整个系统提供." 单例模式实现方式有多种,例如懒汉模式(等用到时候再实例化),饿汉模式(类加载时就实例化)等,这里用饿汉模式方法 ...

  2. [Java笔记]面向对象-单例模式

    单例模式 目标 使JVM中最多只有一个该类的实例,以节省内存.缺点:只能建一个该类的实例. 实现 具体实现思路: 1构造方法私有化//故在外面不能new很多次 2对外提供一个公开的静态的类方法,获取类 ...

  3. java笔记整理

    Java 笔记整理 包含内容     Unix Java 基础, 数据库(Oracle jdbc Hibernate pl/sql), web, JSP, Struts, Ajax Spring, E ...

  4. Effective Java笔记一 创建和销毁对象

    Effective Java笔记一 创建和销毁对象 第1条 考虑用静态工厂方法代替构造器 第2条 遇到多个构造器参数时要考虑用构建器 第3条 用私有构造器或者枚举类型强化Singleton属性 第4条 ...

  5. java 设计模式之单例模式

    -------Success is getting what you want, happiness is wanting what you get. java设计模式之单例模式(Singleton) ...

  6. 【面试题002】java实现的单例模式,c++实现单例模式,实现禁止拷贝

    [面试题002]java实现的单例模式,c++实现单例模式,实现禁止拷贝  一 c++实现单例模式 保证一个类,在一个程序当中只有一个对象,只有一个实例,这个对象要禁止拷贝,注意这里要区别于java. ...

  7. java笔记00-目录

    --2013年7月26日17:49:59 学习java已久,趁最近有空,写一个总结: java笔记01-反射:

  8. php设计模式笔记:单例模式

    php设计模式笔记:单例模式 意图: 保证一个类仅有一个实例,并且提供一个全局访问点 单例模式有三个特点: 1.一个类只有一个实例2.它必须自行创建这个实例3.必须自行向整个系统提供这个实例 主要实现 ...

  9. java中的单例模式与静态类

    单例模式与静态类(一个类,所有方法为静态方法)是另一个非常有趣的问题,在<Java中有关单例模式的面试问题>博文中露掉了,由于单例模式和静态类都具有良好的访问性,它们之间有许多相似之处,例 ...

  10. java的设计模式 - 单例模式

    java 面试中单例模式基本都是必考的,都有最推荐的方式,也不知道问来干嘛.下面记录一下 饿汉式(也不知道为何叫这个名字) public class Singleton { private stati ...

随机推荐

  1. Ubuntu Touch环境搭建

    最近搞了一下Nexus 5的MultiRom Manger,体验了一把Ubuntu Touch和Android L,总体感觉还不错,不过Android L的NFC驱动还有问题,Ubuntu Touch ...

  2. tarjan算法和Kosaraju算法

    tarjan算法和Kosaraju算法是求有向图的强连通分量的算法: #include<iostream> #include<cstring> using namespace ...

  3. 工作管理 (job control)

    这个工作管理 (job control) 是用在 bash 环境下的,也就是说:『当我们登入系统取得创建的 bash shell 进程之后,在该bush下同时进行多个工作的行为管理 』. 而所有创建的 ...

  4. rest_framework 权限流程

    权限流程 权限流程与认证流程非常相似,只是后续操作稍有不同 当用户访问是 首先执行dispatch函数,当执行当第二部时: #2.处理版本信息 处理认证信息 处理权限信息 对用户的访问频率进行限制 s ...

  5. Centos 下,配置 Apache + Python + Django + postgresSQL 开发环境

    用 Python 搭建一个 Web 服务器 文章结构 一.安装  Apache.Python.django 二.安装 mod_wsgi,Apache 为 Python 提供的 wsgi 模块  三.将 ...

  6. css样式表中的样式覆盖顺序(转)

    有时候在写CSS的过程中,某些限制总是不起作用,这就涉及了CSS样式覆盖的问题,如下 Css代码   #navigator { height: 100%; width: 200; position:  ...

  7. AC日记——[JSOI2008]火星人prefix bzoj 1014

    1014 思路: 平衡树+二分答案+hash: 好了懂了吧. 代码: #include <cstdio> #include <cstring> #include <ios ...

  8. php中的int参数

    PHP的函数有很多都会有一个int参数,这些参数基本都是定义为一个常量,虽然不知道有啥用,先记录一下 他们对应的数字 1. htmlspecialchars(),htmlentities() http ...

  9. Apache Kafka 企业级消息队列

    1.大纲 了解 Apache Kafka是什么 掌握Apache Kafka的基本架构 搭建Kafka集群 掌握操作集群的两种方式 了解Apache Kafka高级部分的内容 2.消息系统的作用是什么 ...

  10. 单词接龙(dragon)(BFS)

    单词接龙(dragon) 时间限制: 1 Sec  内存限制: 64 MB提交: 12  解决: 5[提交][状态][讨论版] 题目描述 单 词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已 ...