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;  
    }  
}

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

懒汉模式

public class Singleton {
    private static Singleton singleton;
    private Singleton() {
    }

 public static Singleton getInstance() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}

这种模式没有在加载时实例化对象,而是在调用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();
    }
}

为什么要双重校验

    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;
    }

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

为什么使用volatile加双锁

                if (instance == null) {
                    instance = new Singleton();//erro
                }

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

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

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

  • 在堆中开辟对象所需空间,分配地址
  • 将内存地址返回给栈中的引用变量(此时变量已不在为null,但是变量却并没有初始化完成)
  • 根据类加载的初始化顺序进行初始化
    在这里插入图片描述
    参考:双重校验锁实现单例模式
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值