• TCP的滑动窗口、单例模式(懒汉饿汉)双检锁/双重校验锁(DCL,即 double-checked locking)


    TCP的滑动窗口

    知乎视频解释:网络传输原理:什么是TCP滑动窗口
    在这里插入图片描述

    网络编程之滑动窗口 (TCP流量控制)

    单例模式(懒汉饿汉)

    传统课本上单例模式分两种,一种饿汉式,一种懒汉式。对应的代码如下:
    详解双重饿汉模式和懒汉模式:单例模式中的懒汉模式,饿汉模式 , 双检锁/双重校验锁

    饿汉式

    public class Singleton {  
        private static Singleton instance = new Singleton();   // 在类加载的时候就会实例化  
        private Singleton (){}  
        public static Singleton getInstance() {  
        return instance;  
        }  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    饿汉式在类加载时就实例化对了,使用时直接调用 getInstance() 方法。这个模式为线程安全的,在多线程并发模式下不会重复实例化对象。
    优点: 效率高 缺点: 对象实例化过早,浪费内存资源

    懒汉模式

    public class Singleton {
        private static Singleton singleton;
        private Singleton() {
        }
    
     public static Singleton getInstance() {
            if (singleton == null) {
                singleton = new Singleton();
            }
            return singleton;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    这种模式没有在加载时实例化对象,而是在调用getInstance() 方法时实例化对象,使用懒汉式是为了避免过早的实例化,减少内存资源浪费。
    优点:第一次调用才初始化,避免内存浪费。 缺点: 只适合单线程,线程不安全

    参考:用单例模式来讲讲线程安全
    双检锁/双重校验锁(DCL,即 double-checked locking)
    参考:双检锁/双重校验锁(DCL,即 double-checked locking)详细解析

    public class Singleton {
        private volatile static Singleton instance;
    
        private Singleton() {
        }
    
        public static Singleton getInstance() {
            if (instance == null) {
                synchronized (Singleton.class) {
                    if (instance == null) {
                        instance = new Singleton();//erro
                    }
                }
            }
            return instance;
        }
    
        public static void main(String[] args) {
            Singleton.getInstance();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    为什么要双重校验

        public static Singleton getInstance() {
            if (instance == null) {//线程1,2同时到达,均通过(instance == null)判断。
                                    // 线程1进入下面的同步块,线程2被阻塞
                synchronized (Singleton.class) {
                    if (instance == null) {//线程1执行发现instance为null,初始化实例后,释放锁。
                        // 线程2进入同步块,此次instance已经被初始化。无法通过if条件,避免多次重复初始化。
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    执行双重检测是因为,如果多个线程通过了第一次检测,此时因为synchronized,其中一个线程会首先通过了第二次检测并实例化了对象,剩余的线程不会再重复实例化对象。这样,除了初始化的时候会加锁,后续的调用都是直接返回,解决了多余的性能消耗。

    为什么使用volatile加双锁

                    if (instance == null) {
                        instance = new Singleton();//erro
                    }
    
    • 1
    • 2
    • 3

    如果不使用volatile关键字,隐患来自于上述代码中注释了 erro 的一行,这行代码大致有以下三个步骤:

    • 在堆中开辟对象所需空间,分配地址
    • 根据类加载的初始化顺序进行初始化
    • 将内存地址返回给栈中的引用变量

    由于 Java 内存模型允许“无序写入”,有些编译器因为性能原因,可能会把上述步骤中的 2 和 3 进行重排序,顺序就成了

    • 在堆中开辟对象所需空间,分配地址
    • 将内存地址返回给栈中的引用变量(此时变量已不在为null,但是变量却并没有初始化完成)
    • 根据类加载的初始化顺序进行初始化
      在这里插入图片描述
      参考:双重校验锁实现单例模式
  • 相关阅读:
    Android Audio实战——音量设置Hal(二十)
    线程同步
    Javase | StringBuffer、StringBuilder
    Polygon zkEVM R1CS与Plonk电路转换
    【新书推荐】Cleaning Data for Effective Data Science
    Nginx+Tomcat
    电容如何能做升压?(电荷泵的工作原理及特性)
    Spring(一)Spring配置、构造注入、bean作用域、bean自动装配
    【Redis】高可用:主从复制详解
    Web前端系列技术之Web APIs基础(从基础开始)③
  • 原文地址:https://blog.csdn.net/m0_46378271/article/details/125899790