设计模式——单例模式

介绍

单例(Singleton Pattern)是设计模式中最简单的一种。属于创建型模式。它提供了一种创建对象的最佳方式,即内存中只有一个实例。也就是不会有人使用 new Singleton()来生成一个新的对象。

意图

保证一个类仅有一个实例,并提供一个访问它的全局方法。

解决

一个全局使用的类频繁的创建与销毁。

优点

  1. 内存中只有 一个实例,减少了内存开销,避免了频繁的创建及销毁实例;

  2. 避免对资源的多重占用(写文件操作);

缺点

没有接口,不能继承,与单一原则冲突,一个类应该只关心内部逻辑,而不关系外部怎样实例化。

使用场景

  1. 系统产生唯一序列号;

  2. WEB中的计数器,不用每次刷新在数据库中加一次,使用单例先缓存起来;

UML

示例

  1. 最常用的一种,也是最简单的一种

    饿汉模式:(推荐)

    /*
     * 功能描述:
     * 〈饿汉式单例模式
     * 类加载到内存后,就实例化一个单例,JVM保证线程安全
     * 简单实用,推荐使用
     * 缺点:不管用到与否,类装载时完成实例化。
     * 〉
     *
     * @author : geoary
     * @date : 2019/12/10 21:33
     */
    public class Mgr01 {
        private static final Mgr01 INSTANCE = new Mgr01();
        // 私有的构造函数
        private Mgr01(){
    
        }
    
        // 获取唯一对象实例
        public static Mgr01 getInstance(){
            return INSTANCE;
        }
    
        public static void main(String[] args) {
            Mgr01 mgr01 = Mgr01.getInstance();
            Mgr01 mgr02 = Mgr01.getInstance();
            System.out.println(mgr01 == mgr02);
        }
    }
    
  2. 懒加载模式1:

    /**
     * 功能描述:
     * 〈懒加载
     *  虽然达到了按需初始化的目的,但是带来了线程不安全问题
     * 〉
     *
     * @author : geoary
     * @date : 2019/12/10 21:53
     */
    public class Mgr03 {
        private static Mgr03 INSTANCE;
    
        private Mgr03() {
    
        }
    
        public static Mgr03 getInstance() {
            if (INSTANCE == null) {
                try {
                    Thread.sleep(1);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                INSTANCE = new Mgr03();
            }
            return INSTANCE;
        }
    
        public static void main(String[] args) {
            for (int i = 0; i < 100; i++) {
                /*new Thread(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println(Mgr03.getInstance().hashCode());
                    }
                }).start();*/
    
                new Thread(() -> System.out.println(Mgr03.getInstance().hashCode())).start();
            }
        }
    }
    
  3. 懒加载模式2:

    /**
     * 功能描述:
     * 〈懒加载
     *  通过 synchronized 解决线程问题,但是效率下降
     * 〉
     *
     * @author : geoary
     * @date : 2019/12/10 21:59
     */
    public class Mgr04 {
        private static Mgr04 INSTANCE;
    
        private Mgr04(){
    
        }
        public static synchronized Mgr04 getInstance(){
            if (INSTANCE == null){
                try {
                    Thread.sleep(1);
                }catch (Exception e){
                    e.printStackTrace();
                }
                INSTANCE = new Mgr04();
            }
            return INSTANCE;
        }
    
        public static void main(String[] args) {
            for (int i=0;i<100;i++){
                new Thread(()-> System.out.println(Mgr04.getInstance().hashCode())).start();
            }
        }
    }
    
  4. 静态内部类

    /**
     * 功能描述:
     * 〈静态内部类
     *  jvm 保证单例
     * 〉
     *
     * @author : geoary
     * @date : 2019/12/10 22:12
     */
    public class Mgr07 {
        private Mgr07(){
    
        }
        private static class Mgr07Holder{
            private final static Mgr07 INSTANCE = new Mgr07();
        }
    
        public static Mgr07 getInstance(){
            return Mgr07Holder.INSTANCE;
        }
    
        public static void main(String[] args) {
            for (int i=0; i<100; i++){
                new Thread(()-> System.out.println(Mgr07.getInstance().hashCode())).start();
            }
        }
    }
    

    以上提供了几种实现单例模式的方式,其中最实用的是第一个饿汉模式,虽然会在类装载的时候完成实例化,但是使用简单而且线程安全。

应用场景demo

  1. 全局序列生成器

Singleton.java

package cn.geoaryblog.design.cretedg.single;

public class Singleton {
   private static final Singleton INSTANCE = new Singleton();
   private int num = 0;
   private String name = "默认姓名";

   public static Singleton getInstance() {
       return INSTANCE;
   }

   // 获取序列
   public static int getNextSeq(){
       INSTANCE.num += 1;
       return INSTANCE.num;
   }
}

SingleMain.java

package cn.geoaryblog.design.cretedg.single;

public class SingleMain {
    public static void main(String[] args) {
        // 多个线程是否调用同一个实例
        for (int i = 0; i < 20; i++) {
            new Thread(() -> {
                System.out.println("线程查询到的序列是:" + Singleton.getNextSeq());
            }).start();
        }
    }
}
posted @   Geoary  阅读(34)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示