GOF之单例模式(创建型模式) ✨每日积累

简介: GOF之单例模式(创建型模式) ✨每日积累

单例模式是什么


创造型设计模式,负责自己创建自己的对象,构造器私有化,不允许外界直接new自己,确保每一次都只有单个对象被创建,这个类提供了一种访问自身对象的一个入口,可以直接访问。优点是可以在内存中只有一个实例,减少了内存的开销,尤其是频繁创建和销毁实例;还有对资源的多重占用(例如写io操作)。缺点就是不能继承,没有接口,与单一职责冲突,一个类只关心自己创建自己对象的逻辑,不关心外面如何实例化。


何时使用单例模式

当整个软件系统中,对某个类只能存在一个实例对象的情况下我们可以使用单例模式。具体使用那种单例,需要结合业务场景。


单例模式三个特点

1、单例类只能有一个实例。

2、单例类必须自己创建自己的唯一实例。

3、单例类必须给所有其他对象提供这一实例。

JDK中Runtime使用单例模式

饿汉式

1.png

单例模式实现的几种方式

1、懒汉试

/**
 * 懒加载,第一次调用才初始化,避免内存浪费
 */
public class TestLazySingleton {
    private static TestLazySingleton testLazySingleton;
    private TestLazySingleton(){}
    //线程不安全,单线程正常工作,多线程情况下并非单例
    public static TestLazySingleton getInstance(){
        if (testLazySingleton == null) return testLazySingleton = new TestLazySingleton();
        return testLazySingleton;
    }
    //线程安全,加锁,效率低
    public static synchronized TestLazySingleton getInstanceSafe(){
        if (testLazySingleton == null) return testLazySingleton = new TestLazySingleton();
        return testLazySingleton;
    }
}

2、饿汉试

/**
 * 饿汉试:比较常用,非懒加载,项目启动即加载(非使用才加载),浪费内存容易产生垃圾对象。
 * 它基于 classloader 机制避免了多线程的同步问题
 */
public class TestHungrySingleTon{
    private static TestHungrySingleTon testHungrySingleTon = new TestHungrySingleTon();
    private TestHungrySingleTon(){}
    public static TestHungrySingleTon getInstance(){
        return testHungrySingleTon;
    }
}

3、双重锁/校验机制

/**
 * 双重校验机制:懒加载机制,线程安全,可在多线程保持高性能
 */
public class TestDoubleCheckedLocking{
    //此处使用volatile是防止类初始化是发生指令重排,导致对象初始化半成品对象就被其他线程使用了
    private volatile static TestDoubleCheckedLocking testDoubleCheckedLocking;
    private TestDoubleCheckedLocking (){}
    public static TestDoubleCheckedLocking getSingleton() {
        if (testDoubleCheckedLocking == null) {
            synchronized (TestDoubleCheckedLocking.class) {
                if (testDoubleCheckedLocking == null) {
                    testDoubleCheckedLocking = new TestDoubleCheckedLocking();
                }
            }
        }
        return testDoubleCheckedLocking;
    }
}

4、登记式/静态内部类

/**
 * 登记式/静态内部类:懒加载,节省内存。线程安全,利用了 classloader 机制来保证初始化 instance 时只有一个线程。
 */
public class TestRegistrationSingleton{
    private TestRegistrationSingleton(){}
    private static class GetRegistrationSingletonUtil{
        private static final TestRegistrationSingleton SINGLETON_INSTANCE = new TestRegistrationSingleton();
    }
    public static final TestRegistrationSingleton getInstance(){
        return GetRegistrationSingletonUtil.SINGLETON_INSTANCE;
    }
}

5、枚举

public enum TestEnumSingleton {
    INSTANCE;
    public void whateverMethod() {
    }
    public static void main(String[] args) {
        TestEnumSingleton testEnumSingleton = TestEnumSingleton.INSTANCE;
        TestEnumSingleton testEnumSingletonV2 = TestEnumSingleton.INSTANCE;
        CurrentExistingSingleton currentExistingSingleton = CurrentExistingSingleton.SingletonEnum.SINGLETON.getInstance();
        CurrentExistingSingleton currentExistingSingletonV2 = CurrentExistingSingleton.SingletonEnum.SINGLETON.getInstance();
        //都是true
        System.out.println(testEnumSingleton == testEnumSingletonV2);
        System.out.println(currentExistingSingleton == currentExistingSingletonV2);
    }
}
/**
 * 对现存类的加入单例功能的扩展
 */
class CurrentExistingSingleton {
    private CurrentExistingSingleton() {
    }
    public static enum SingletonEnum {
        SINGLETON;
        private CurrentExistingSingleton instance = null;
        private SingletonEnum() {
            instance = new CurrentExistingSingleton();
        }
        public CurrentExistingSingleton getInstance() {
            return instance;
        }
    }
}

使用场景

一般情况下,不建议使用第 1 种懒汉方式,建议使用第 2 种饿汉方式。只有在要明确实现 lazy loading 效果时,才会使用第 4 种登记方式。如果涉及到反序列化创建对象时,可以尝试使用第5 种枚举方式。如果有其他特殊的需求,可以考虑使用第 3 种双检锁方式。


单例模式实践

参考https://blog.csdn.net/lovelion/article/details/7420885文章


实践负载均衡器的设计与实现

将负载均衡器LoadBalancer设计为单例类,其中包含一个存储服务器信息的集合serverList,每次在serverList中随机选择一台服务器来响应客户端的请求

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* 使用单例实现简单的负载均衡功能
*/
public class TestLoadBalancer {
   //懒加载模式
   private static TestLoadBalancer testLoadBalancer;
   //服务器集合
   private List serverList;
   //私有化构造,禁止外界直接new实例
   private TestLoadBalancer(){
       serverList = new ArrayList();
   }
   /**
    * 使用枚举:在SingletonEnum中定义了枚举类型的实例对象Singleton,
    * 再按照单例模式的要求在其中定义一个Singleton类型的对象instance,其初始值为null;
    * 我们需要将SingletonEnum的构造函数改为私有的,在私有构造函数中创建一个Singleton的实例对象;
    * 最后在getInstance()方法中返回该对象。
    */
   public static enum SingletonEnum{
       SINGLETON;
       private SingletonEnum() {
           testLoadBalancer = new TestLoadBalancer();
       }
       public TestLoadBalancer getInstance() {
           return testLoadBalancer;
       }
   }
   //增加服务器
   public void addServer(String server) {
       serverList.add(server);
   }
   //删除服务器
   public void removeServer(String server) {
       serverList.remove(server);
   }
   //使用Random类获取服务器
   public String getServer(){
       Random random = new Random();
       int i = random.nextInt(serverList.size());
       return String.valueOf(serverList.get(i));
   }
   public void testSimulationClient(){
       TestLoadBalancer clientV1 = SingletonEnum.SINGLETON.getInstance();
       TestLoadBalancer clientV2 = SingletonEnum.SINGLETON.getInstance();
       TestLoadBalancer clientV3 = SingletonEnum.SINGLETON.getInstance();
       TestLoadBalancer clientV4 = SingletonEnum.SINGLETON.getInstance();
       TestLoadBalancer clientV5 = SingletonEnum.SINGLETON.getInstance();
       //判断服务器是否一致
       if (clientV1 == clientV2 &&  clientV2 == clientV3 && clientV3 == clientV4 && clientV4 == clientV5){
           System.out.println("服务器负载均衡器具有唯一性!");
       }
       //增加服务器
       clientV1.addServer("Server 1");
       clientV1.addServer("Server 2");
       clientV1.addServer("Server 3");
       clientV1.addServer("Server 4");
       //模拟客户端请求的分发
       for (int i = 0; i < 10; i++) {
           String server = clientV1.getServer();
           System.out.println("分发请求至服务器: " + server);
       }
   }
   public static void main(String[] args) {
       new TestLoadBalancer().testSimulationClient();
   }
}
相关实践学习
部署高可用架构
本场景主要介绍如何使用云服务器ECS、负载均衡SLB、云数据库RDS和数据传输服务产品来部署多可用区高可用架构。
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
相关文章
|
8月前
|
设计模式 Java
Java设计模式解析:工厂模式的奥秘
当谈论Java设计模式时,"工厂模式"无疑是一个不容忽视的重要主题。在本文中,我们将深入探讨工厂模式,探索它的概念、应用场景以及在Java中的具体实现。
39 0
|
4月前
|
设计模式 Java Spring
|
设计模式
GOF之工厂模式(创建型模式) ✨ 每日积累
GOF之工厂模式(创建型模式) ✨ 每日积累
GOF之工厂模式(创建型模式) ✨ 每日积累
GOF之装饰器模式(结构型模式) ✨ 每日积累
GOF之装饰器模式(结构型模式) ✨ 每日积累
GOF之装饰器模式(结构型模式) ✨ 每日积累
GOF之抽象工厂模式(创建型模式) ✨ 每日积累
GOF之抽象工厂模式(创建型模式) ✨ 每日积累
GOF之抽象工厂模式(创建型模式) ✨ 每日积累
|
开发者
GOF之桥接模式(结构型模式) ✨ 每日积累
GOF之桥接模式(结构型模式) ✨ 每日积累
GOF之桥接模式(结构型模式) ✨ 每日积累
GOF之适配器模式(结构型模式) ✨ 每日积累
GOF之适配器模式(结构型模式) ✨ 每日积累
GOF之适配器模式(结构型模式) ✨ 每日积累
GOF之建造者模式(创建型模式)附图详解 ✨ 每日积累
GOF之建造者模式(创建型模式)附图详解 ✨ 每日积累
GOF之建造者模式(创建型模式)附图详解 ✨ 每日积累
|
设计模式 存储 安全
GOF设计模式之组合设计模式(结构型模式) ✨ 每日积累
GOF设计模式之组合设计模式(结构型模式) ✨ 每日积累
GOF设计模式之组合设计模式(结构型模式) ✨ 每日积累
|
设计模式 存储 JavaScript
白话讲解创建型设计模式:单例、原型,构建
关于设计模式,个人觉得,在理解上要站在问题域的角度,而不是它的实现方式,因为学完全部的设计模式,你会感觉,好像大多设计模式实现上基本一样。往往有这一种被欺骗的感觉....哈
127 1