折腾Java设计模式之单例模式

博文原址:折腾Java设计模式之单例模式

单例模式

Ensure a class has only one instance, and provide a global point of access to it.

一个类仅仅只有一个实例,并且提供全局的接入点。简洁点理解就是涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问它自己唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

饿汉式单例模式

public final class EagerSingleton {

    private static final EagerSingleton INSTANCE = new EagerSingleton();

    private EagerSingleton() {
    }

    public static EagerSingleton getInstance() {
        return INSTANCE;
    }
}

基于 classloader 机制避免了多线程的同步问题,不过INSTANCE在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用 getInstance 方法。类在加载时就初始化了,会浪费空间,因为不管你用还是不用,它都创建出来了,但是因为没有加锁,执行效率较高。

懒汉式单例模式

/**
 * 懒汉式的单例模式-线程不安全的
 */
public final class LazyThreadNotSafeSingleton {

    private static LazyThreadNotSafeSingleton INSTANCE;

    private LazyThreadNotSafeSingleton() {
    }

    public static LazyThreadNotSafeSingleton getInstance() {
        if (null == INSTANCE) {
            INSTANCE = new LazyThreadNotSafeSingleton();
        }
        return INSTANCE;
    }
}
/**
 * 懒汉式的单例模式-线程安全的
 */
public final class LazyThreadSafeSingleton {

    private static LazyThreadSafeSingleton INSTANCE;

    private LazyThreadSafeSingleton() {
    }

    public static synchronized LazyThreadSafeSingleton getInstance() {
        if (null == INSTANCE) {
            INSTANCE = new LazyThreadSafeSingleton();
        }
        return INSTANCE;
    }
}

有上述两种懒汉式单例模式,区别在与静态工厂方法getInstance是否加了synchronized修饰来进行同步,用于支持线程安全。懒汉式,在其加载对象的时候是不会创建对象实例的,只有等它真正使用的时候才会创建,如果一直没有使用则一直不会创建,能够避免内存浪费,也就是只有第一次调用的时候才会创建。但是加锁synchronized就影响了性能和效率,导致getInstance方法的性能受影响,此种方式也不推荐。寻找一种既能线程安全又可以延迟加载的方式。

双检查锁的单例模式

/**
 * 双检查锁的单例模式-线程安全
 */
public final class DoubleCheckLockingSingleton {

    private static volatile DoubleCheckLockingSingleton INSTANCE;

    private DoubleCheckLockingSingleton() {
    }

    public static DoubleCheckLockingSingleton getInstance() {
        // 第一次检查实例是否存在,如果存在即可返回,不存在则进入同步块
        if (null == INSTANCE) {
            // 同步块,线程安全
            synchronized (DoubleCheckLockingSingleton.class) {
                // 第二次检查实例是否存在,如果还不存在则会真正的创建实例
                if (null == INSTANCE) {
                    INSTANCE = new DoubleCheckLockingSingleton();
                }
            }
        }
        return INSTANCE;
    }
}

双检查加锁的方式,能实现线程安全,又能减少性能的影响。双检查加锁,旨在每次调用getInstance方法都需要同步,但是先不会同步,在第一次判断实例是否存在后,如果不存在才进入同步块,进入同步块后,第二次检查实例是否存在,如果不存在,在同步块内创建实例。如此只有首次才会同步,从而减少了多次在同步情况下进行判断所浪费的时间。双检查加锁机制的实现会使用关键字volatile,它的意思是:被volatile修饰的变量的值,将不会被本地线程缓存,所有对该变量的读写都是直接操作共享内存,从而确保多个线程能正确的处理该变量。但是实现过程稍微复杂点。

静态内部类Holder式单例模式

/**
 * 静态内部类Holder式单例
 *
 * 延迟加载和线程安全
 */
public final class LazyInitializationHolderSingleton {

    private LazyInitializationHolderSingleton() {
    }

    public static LazyInitializationHolderSingleton getInstance() {
        return InstanceHolder.INSTANCE;
    }

    /**
     * 延迟加载
     */
    private static class InstanceHolder {

        private static final LazyInitializationHolderSingleton INSTANCE = new LazyInitializationHolderSingleton();
    }
}

getInstance方法第一次被调用的时候,它第一次读取InstanceHolder.INSTANCE,导致InstanceHolder类得到初始化;而这个类在装载并被初始化的时候,会初始化它的静态域,从而创建Singleton的实例,由于是静态的域,因此只会在虚拟机装载类的时候初始化一次,并由虚拟机来保证它的线程安全性。这个模式的优势在于,getInstance方法并没有被同步,并且只是执行一个域的访问,因此延迟初始化并没有增加任何访问成本。其中使用到类的静态内部类和多线程缺省同步锁。

静态内部类

静态内部类指,有static修饰的成员式内部类。如果没有static修饰的成员式内部类被称为对象级内部类。类级内部类相当于其外部类的static成分,它的对象与外部类对象间不存在依赖关系,因此可直接创建。而对象级内部类的实例,是绑定在外部对象实例中的。静态内部类中,可以定义静态的方法。在静态方法中只能够引用外部类中的静态成员方法或者成员变量。静态内部类相当于其外部类的成员,只有在第一次被使用的时候才被会装载。

多线程缺省同步锁

在多线程开发中,为解决并发问题,主要是通过使用synchronized来加互斥锁进行同步控制。但是在某些情况中,JVM已经隐含地为您执行了同步,这些情况下就不用自己再来进行同步控制了。这些情况包括:

1.由静态初始化器(在静态字段上或static{}块中的初始化器)初始化数据时;

2.访问final字段时;

3.在创建线程之前创建对象时;

4.线程可以看见它将要处理的对象时

枚举类型的单例模式

/**
 * 采用枚举类型的单例模式
 */
public enum SingletonEnum {

    INSTANCE;

    @Override
    public String toString() {
        return getDeclaringClass().getCanonicalName() + "@" + hashCode();
    }

    public void something(){
        //do something...
    }

}

简洁,自动支持序列化机制,绝对防止多次实例化。《高效Java 第二版》中的说法:单元素的枚举类型已经成为实现Singleton的最佳方法。用枚举来实现单例非常简单,只需要编写一个包含单个元素的枚举类型即可。

总结

不建议使用懒汉式,简单的阔以使用饿汉式。涉及到反序列化创建对象时阔以使用枚举方式。如果考虑到延迟加载 的话,阔以采用静态内部类Holder的模式。如果对业务需求有特殊要求的时候阔以采用双检查锁的单例。

参考

源码地址

单例模式|菜鸟教程

《JAVA与模式》之单例模式

欢迎关注了解最新动态更新

原文地址:https://blog.51cto.com/6271727/2384897

时间: 04-24

折腾Java设计模式之单例模式的相关文章

(九)JAVA设计模式之单例模式

JAVA设计模式之单例模式 一.单例模式的介绍 Singleton是一种创建型模式,指某个类采用Singleton模式,则在这个类被创建后,只可能产生一个实例供外部访问,并且提供一个全局的访问点.     全局对象和Singleton模式有本质的区别,因为大量使用全局对象会使得程序质量降低,而且有些编程语言根本不支持全局变量.最重要的是传统的全局对象并不能阻止一个类被实例化多次. 二.单例模式的特点 单例类只能有一个实例 单例类必须自己创建自己的唯一实例. 单例类必须给所有其他对象提供这一实例.

java 设计模式之单例模式

--------2015-11-20 14:45:10 java设计模式之单例模式(Singleton): ---应用场合:只需要一个对象就可以了,例如一个朝代一个皇帝. ---作用:保证某个应用程序中某个实例有且只有一个.共同使用一个,节省资源. ---类型:饿汉模式,懒汉模式. 一.饿汉模式(类加载的时候就会实例化,线程安全) 1 package com.sun.singleton; 2 3 //饿汉模式 4 public class Singleton { 5 6 //将构造函数私有化,不

java设计模式之单例模式(Singleton)

Java设计模式之单例模式 单例模式是什么? 保证一个类仅有一个实例,并提供一个访问它的全局访问点. 单例模式如何来设计呢? 保证一个类只能有一个实例,那么我们不能无限制的new 来创建,因为我们知道,new一次就是一个新的对象,那么构造器只能私有化private -- 构造器私有化 构造器私有化了,问题又出现了,构造器私有化了,那么我们怎么来创建唯一的对象呢?-- 提供一个公有的方法/提供一个公有的静态属性 再分析一下,公有方法, 实例方法还是类方法呢?--公有的类方法(获取类实例) 依据以上

java设计模式之单例模式(Singleton pattern)

java设计模式之单例模式(Singleton pattern) 单例模式的定义: Singleton pattern restricts the instantiation of a class and ensures that only one instance of the class exists in the java virtual machine. The singleton class must provide a global access point to get the i

Java设计模式之单例模式(七种写法)

Java设计模式之单例模式(七种写法) 第一种,懒汉式,lazy初始化,线程不安全,多线程中无法工作: public class Singleton { private static Singleton instance; private Singleton (){}//私有化构造方法,防止类被实例化 public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } retu

折腾Java设计模式之备忘录模式

原文地址:折腾Java设计模式之备忘录模式 备忘录模式 Without violating encapsulation, capture and externalize an object's internal state allowing the object to be restored to this state later. 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态. 所谓备忘录模式就是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个

折腾Java设计模式之中介者模式

博文原址:折腾Java设计模式之中介者模式 中介者模式 中介者模式(Mediator Pattern)是用来降低多个对象和类之间的通信复杂性.这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护.中介者模式属于行为型模式. 通俗点来讲就是提供一个中介平台,说到平台,那其实很容易联系到我们很熟悉的房地产中介.我们可以直接通过这个平台得到我们想要的信息,不用对象自身与其他对象交互. 买房子租房子就不需要去找房东,只需要在中介那里获取相应的×××信息.如下图那样,两方只

Java设计模式:单例模式

概念: java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建自己的唯一实例. 3.单例类必须给所有其他对象提供这一实例. 单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例.在计算机系统中,线程池.缓存.日志对象.对话框.打印机.显卡的驱动程序对象常被设计成单例.这些应用都或多或少具有资源管理器的功能.每台计算机可以有若干个打印机,但只能

[转]JAVA设计模式之单例模式

原文地址:http://blog.csdn.net/jason0539/article/details/23297037 概念: java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建自己的唯一实例. 3.单例类必须给所有其他对象提供这一实例. 单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例.在计算机系统中,线程池.缓存.日志对象.对话