二、单例模式之单例模式

单例模式创建方式有以下几种方式:

  1. 饿汉模式
  2. 懒汉模式
  3. 注册式模式
  4. 枚举式模式
  5. 序列化模式

1.饿汉模式

在类加载时初始化,也是利用类加载线程安全的特性确保了单例实例化的线程安全。

package com.kancy.pattern.single;

/**
 * 单例模式 - 饿汉模式
 * @author kancy
 */
public class HungerSingleton {
    /**
     * 在类加载时初始化好单例对象,利用类加载来保证单例初始化的线程安全
     * 优点:不用任何锁就能保证绝对线程安全,执行效率高
     * 缺点:由于类加载时就分配内存空间,初始化。如果以后使用不到改对象,就会造成一定程度内存空间的浪费。
     */
    private static HungerSingleton ourInstance = new HungerSingleton();
    private HungerSingleton() {
    }
    public static HungerSingleton getInstance() {
        return ourInstance;
    }
}

2.懒汉模式

1)方式一:

package com.kancy.pattern.single;

/**
 * 单例模式 - 懒汉模式01
 * @author kancy
 */
public class LazySingleton01 {
    /**
     * 单例被使用时才创建实例对象,不会造成内存空间浪费,但会存着数据安全问题:
     *      两个线程同一时刻判断instance == null 时,都会去创建对象,后者会覆盖前者引用。
     */
    private static LazySingleton01 instance;
    private LazySingleton01() {
    }
    public static LazySingleton01 getInstance(){
        if(instance == null){
            instance = new LazySingleton01();
        }
        return instance;
    }
}

2)方式二:

package com.kancy.pattern.single;

/**
 * 单例模式 - 懒汉模式02
 * @author kancy
 */
public class LazySingleton02 {
    /**
     * 单例被使用时才创建实例对象,不会造成内存空间浪费,但会存着数据安全问题:
     *      两个线程同一时刻判断instance == null 时,都会去创建对象,后者会覆盖前者引用。
     *  加上方法可见锁,确保线程安全,但同时会较低执行效率,性能下降。
     */
    private static LazySingleton02 instance;
    private LazySingleton02() {
    }
    public synchronized static LazySingleton02 getInstance(){
        if(instance == null){
            instance = new LazySingleton02();
        }
        return instance;
    }
}

3)方式三:

package com.kancy.pattern.single;

/**
 * 单例模式 - 懒汉模式03
 * @author kancy
 */
public class LazySingleton03 {
    /**
     * 单例被使用时才创建实例对象,不会造成内存空间浪费,但会存着数据安全问题:
     *      两个线程同一时刻判断instance == null 时,都会去创建对象,后者会覆盖前者引用。
     *  使用对象锁,缩小锁的范围,确保线程安全的同时,减小性能的损失
     */
    private static volatile LazySingleton03 instance; // 保证对象在内存中的可见性
    private LazySingleton03() {
    }
    public static LazySingleton03 getInstance(){
        if(instance == null){
            synchronized (LazySingleton03.class){
                // double check,防止对象没有初始化完整时,第二个线程再次进来进行初始化
                if(instance == null){
                    instance = new LazySingleton03();
                }
            }
        }
        return instance;
    }
}

4)方式四:

package com.kancy.pattern.single;

import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 单例模式 - 懒汉模式04
 * @author kancy
 */
public class LazySingleton04 {
    /**
     * 可以通过反射修改initFlg再次进行反射初始化对象,目前没有好的办法解决
     *  但一般没人这么无聊吧!!!
     */
    private static AtomicBoolean initFlg = new AtomicBoolean(false);
    private LazySingleton04() {
        // 防止反射入侵:不允许再次创建实例
        if(!initFlg.get()){
            initFlg.set(true);
        }else{
            throw new RuntimeException("单例被反射入侵");
        }
    }
    /**
     * 利用内部类加载的机制巧妙的实现单例的线程安全。
     * 内部类在使用时才会进行类加载。
     * 当调用getInstance方法时,才会把内部类LazySingleton04Holder加载到内存,同时线程安全的初始化LazySingleton04实例。
     * 这样既可以保证线程安全,也可以减少内存浪费的机会。
     */
    public static LazySingleton04 getInstance(){
        return LazySingleton04Holder.instance;
    }
    private static class LazySingleton04Holder{
        private static final LazySingleton04 instance = new LazySingleton04();
    }
}

效率从高到低:LazySingleton04 - > LazySingleton01 -> LazySingleton03 -> LazySingleton02,所以推荐使用第四种。

3.注册式

把单例注册到容器中,有则取出,无则创建并注册

package com.kancy.pattern.single;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 单例模式 - 注册式单例模式
 */
public class RegisterSingleton {
    /**
     * 读取实现线程安全
     */
    private static Map<String,Object> ioc = new ConcurrentHashMap();
    public static Object getBean(String className){
        if(!ioc.containsKey(className)){
            try {
                // 创建对象,并且注册到容器当中
                Class<?> aClass = Class.forName(className);
                Object instance = aClass.newInstance();
                // 创建对象到put进入ioc中需要一段时间,可能造成线程不安全
                ioc.put(className, instance);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return ioc.get(className);
    }
}

4.枚举式

package com.kancy.pattern.single;
/**
 * 单例模式 - 常量/枚举式单例模式
 */
public enum EnumSingleton {
    A,B,C;
}

5.序列化方式

序列化:将内存状态转化为字节数组,持久化到磁盘等。

反序列化:将持久化内容转化为java对象。

附上测试类代码:

package com.kancy.pattern.single;

import com.kancy.bean.Person;

import java.io.Serializable;
import java.util.concurrent.CountDownLatch;

public class SingletonTest implements Serializable,Cloneable{

    public static void main(String[] args) {
        testDataSecure();
    }
    /**
     * 测试数据安全
     */
    private static void testDataSecure() {
        int threadCount = 20;
        CountDownLatch count = new CountDownLatch(threadCount);
        for (int i = 0; i < threadCount; i++) {
            new Thread(() -> {
                try {
                    // 等待所有线程都创建好,一起去执行
                    count.await();
                    Object bean = RegisterSingleton.getBean(Person.class.getName());
                    System.out.println(bean);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).start();
            // 线程就绪
            count.countDown();
        }
    }
    /**
     * 懒汉效率从高到底:
     *  LazySingleton04 - > LazySingleton01 -> LazySingleton03 -> LazySingleton02
     */
    private static void testEfficiency() {
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100000000; i++) {
            LazySingleton04.getInstance();
        }
        long end = System.currentTimeMillis();
        System.out.println("用时:" + (end - start));
    }
}

原文地址:https://www.cnblogs.com/kancy/p/10226960.html

时间: 2024-11-08 22:50:55

二、单例模式之单例模式的相关文章

设计模式(二):单例模式

单例模式:用来创建只能有一个实例的对象.确保一个类只有一个实例,并提供一个全局访问点. 有的时候我们不希望一个类被创建出多个对象,因为多个实例会带来许多不好的影响. 经典单例模式: public class SingleInstance { private static SingleInstance instance; private SingleInstance(){} public static SingleInstance getInstance(){ if(instance == nul

题目二:实现单例模式

//////////////////////////////////////////////////////////////////////////////////////////////////////// // 4.单例模式测试 extern CMutex g_stMutex; // 这个在ThreadTest.cpp中定义了,这个声明一下!!!! class CSingletonTest { public: CSingletonTest() :m_iCount(0){} ~CSinglet

什么是单例模式?单例模式有哪些方式实现?写个例子。

什么是单例模式? 我所理解的单例模式:整个程序中只允许有唯一的一个对象(这个类只能实例化一次) 看看我找到的解释:当一个类只能有一个对象时,往往会用到单例模式,例如,现实生活中有很多临界资源,像 打印机.处理器(单核).皇帝.太子等等,它们都是稀有资源,只能有一个实例对象. 单例模式有哪些方式实现? 第一种最简单,但没有考虑线程安全,在多线程时可能会出问题.(懒单例) public class Singleton { private static Singleton _instance = nu

PHP设计模式二:单例模式

一.什么是单例模式 作为对象的创建模式,单例模式确保某一个类只有一个实例,并且对外提供这个全局实例的访问入口.它不会 创建实例副本,而是会向单例类内部存储的实例返回一个引用. 二.PHP单例模式三要素 1. 需要一个保存类的唯一实例的静态成员变量. 2. 构造函数和克隆函数必须声明为私有的,防止外部程序创建或复制实例副本. 3. 必须提供一个访问这个实例的公共静态方法,从而返回唯一实例的一个引用. 三.为什么使用单例模式 使用单例模式的好处很大,以数据库操作为例.若不采用单例模式,当程序中出现大

设计模式(二)单例模式(转)

原文地址:http://www.jellythink.com/archives/82 问题描述 现在,不管开发一个多大的系统(至少我现在的部门是这样的),都会带一个日志功能:在实际开发过程中,会专门有一个日志模块,负责写日志,由于在系统的任何地方,我们都有可能要调用日志模块中的函数,进行写日志.那么,如何构造一个日志模块的实例呢?难道,每次new一个日志模块实例,写完日志,再delete,不要告诉我你是这么干的.在C++中,可以构造一个日志模块的全局变量,那么在任何地方就都可以用了,是的,不错.

从源码中学习设计模式系列——单例模式序/反序列化以及反射攻击的问题(二)

一.前言 这篇文章是学习单例模式的第二篇,之前的文章一下子就给出来看起来很高大上的实现方法,但是这种模式还是存在漏洞的,具体有什么问题,大家可以停顿一会儿,思考一下.好了,不卖关子了,下面我们来看看每种单例模式存在的问题以及解决办法. 二.每种Singleton 模式的演进 模式一 public class LazySingleton { private static LazySingleton lazySingleton = null; private LazySingleton() { }

Python单例模式剖析

在聊这之前我们首先要明确的是,单例模式在实际中的意义以及在python中具有实现的价值? 当前,相信有很多人支持单例模式,也有不少人反对,尤其是在python中,目前依旧具有很大的争议性.我们要在评论之前首先要了解单例模式 什么是单例模式? 顾名思义:就是单个模式 单例模式是一种常见的软件设置模式,在它的核心结构中只包含一个被称为单例类的特殊类,通过单例模式可以保证系统中的一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源.如果希望在系统中某个对象只能存在一个,单例

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

前言: 在总结okHttp的时候,为了管理网络请求使用到了单例模式,晚上实在没啥状态了,静下心来学习总结一下使用频率最高的设计模式单例模式. 单例模式: 单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例. 单例特点: 单例类只能有一个实例. 单例类必须自己创建自己的唯一实例. 单例类必须给所有其他对象提供这一实例. 单例分类: 1).懒汉单例 (1)非线程安全实现 public class Singleton { private Singleton(){ } private

单例模式 (Singleton pattern)

What is Singleton pattern? In Wikipedia, there is an explanation:"In software engineering, the singleton pattern is a design pattern that restricts the instantiation of a class to one object." 一.什么是单例模式? 在维基百科中,是这样解释的,“在软件工程中,单例模式指的是对类加以限制,只允许创建