SpringBoot启动流程
基础流程: Java程序由启动主类调用main()方法开始 根据@SpringBootApplication注解以及调用SpringApplication的构造方法,实例一个Spirng应用对象。在构造方法里主要完成启动环境初始化工作,如推断主类,spring应用类型,加载配置文件,读取spring.factories文件等 调用run方法,所有的启动工作在该方法内完成,主要完成加载配置资源,准备上下文,创建上下文,刷新上下文,过程事件发布等
Bean的生命周期以及IoC的实现原理
Bean的生命周期概要流程单例对象:singleton 生命周期与容器相同 多例对象:prototype 出生:对象时spring框架为我们创建 活着:使用过程 死亡:被gc回收 Bean 的生命周期概括起来就是 4 个阶段: 实例化(Instantiation):new一个对象 属性赋值(Populate):设置对象属性和依赖,也就是IoC注入:按照Spring上下文对实例化的Bean配置 初始化(Initialization):有 Aware 接口的依赖注入、BeanPostProcessor 在初始化前后的处理以及 InitializingBean 和 init-method 的初始化操作 销毁(Destruction):有注册相关销毁回调接口,最后通过DisposableBean 和 destory-method 进行销毁 扩展点的作用AwareAware接口:若 Spring 检测到 bean 实现了 Aware 接口,则会为其注入相应的依赖。所以通过让bean 实现 Aware 接口,则能在 bean 中获得相应的 Spring 容器资源 Spring...
Java信号量——Semaphore
基本概念Semaphore是一个计数信号量,它可以用来控制对某一资源的访问数量。在Java中,Semaphore位于java.util.concurrent包中 Semaphore的用途流量控制:Semaphore可以用来控制同时访问特定资源的线程数量,例如数据库连接、文件句柄等分配资源:Semaphore可以用来分配有限数量的资源,例如线程池、线程队列等 Semaphore的使用技巧 创建Semaphore 1Semaphore semaphore = new Semaphore(5); 获取信号量 1semaphore.acquire(); 请求一个信号量,这时候的信号量个数-1(是尝试获取,如果是>0就减去, 否则阻塞等待信号量>0) 释放信号量 1semaphore.release(); 信号量+1 使用tryAcquire方法 1boolean acquired = semaphore.tryAcquire(); 上述代码尝试获取信号量,如果成功则返回true,否则返回false 使用tryAcquire(long...
深入AQS底层源码
AQS概述AQS是juc包下的一个抽象类,很多juc包下的工具类都是根据AQS是实现的,比如ThreadPoolExecutor、CountDownLatch、ReetrantLock、ReetrantWriteLock、Semaphore AQS的核心内容核心属性state1234/** * The synchronization state. */private volatile int state; 不同的实现,state的意义不同。以ReetrantLock为例: state为0,没有线程持有这个lock锁 state > 0,当前lock锁被某个线程持有 不存在state小于0的情况 同步队列12345678910111213/** * Head of the wait queue, lazily initialized. Except for * initialization, it is modified only via method setHead. Note: * If head exists, its waitStatus is...
JUC同步工具CountDownLatch源码解析,与CyclicBarrier的对比
基本使用CountDownLatch典型用法:某一线程在开始运行前等待n个任务线程数执行完毕。将CountDownLatch的计数器初始化为new CountDownLatch(n),每当一个任务线程数执行完毕,就将计数器减1 countdownLatch.countDown(),当计数器的值变为0时,在CountDownLatch上await()的线程就会被唤醒。一个典型应用场景就是启动一个服务时,主线程需要等待多个组件加载完毕,之后再继续执行 自定义任务类 1234567891011121314151617181920212223242526package org.example; import java.util.Random;import java.util.concurrent.CountDownLatch; public class Task implements Runnable{ private final static Random random = new Random(); private Integer id; ...
跳表节点层数的确定方法
初始化节点层数为1,这是跳表中所有节点的初始层数 对每个节点,通过随机数生成器生成一个介于0和1之间的随机数p 将p与固定的概率因子P进行比较,如果p小于P,则将节点的层数加1 重复步骤2和步骤3,直到p大于或等于P为止 产生越高的节点层数,概率越低。定量的分析如下: 假设概率因子是p,节点层数至少为 1。 而大于 1 的节点层数,满足一个概率分布: 节点层数恰好等于 1 的概率为 1-p 节点层数大于等于 2 的概率为 p,而节点层数恰好等于 2 的概率为 p(1-p) 节点层数大于等于 3 的概率为 p^2,而节点层数恰好等于 3 的概率为 p^2*(1-p) 节点层数大于等于 4 的概率为 p^3,而节点层数恰好等于 4 的概率为 p^3*(1-p) …… 一个节点的平均层数(也即包含的平均指针数目)(期望): 现在很容易计算出: 当 p=1/2 时,每个节点所包含的平均指针数目为 2 当 p=1/4 时,每个节点所包含的平均指针数目为 1.33
IOC的三级缓存以及循环依赖问题
三级缓存 一级缓存<Map, String>singletonObjects:储存最终的完整bean的容器 二级缓存<Map, String>earlySingletonObjects:储存实例化但未初始化的半成品bean 三级缓存<Map,...
Autowired注解注入的对象是单例吗
@Autowired是单例模式,因为它在注入之前,对象已经实例化 通过@Scope(“prototype”),@Autowired注入的也是单例模式 此外,@Autowired+@Qualifier(“student”) 与@Resource作用一致,当获取对象时,并不能稳定获取到多例,在使用时需要注意
JVM堆的大小参数应该怎么设置
JVM堆大小参数的设置需要根据应用程序的需求、可用内存以及性能目标来确定。 可以通过-Xms(初始堆大小)和-Xmx(最大堆大小)参数进行设置。例如,-Xms512m -Xmx2g表示初始堆大小为512MB,最大堆大小为2GB 还有其他一些与堆相关的参数,如-XX:NewRatio用于设置年轻代和老年代的比例,默认值是2,表示年轻代占堆的1/3。比如-XX:NewRatio=2 -XX:SurvivorRatio用于设置Eden区和一个Survivor区的比例,默认值是8,表示Eden区占年轻代的8/10。比如-XX:Survivor=8 此外,还有-XX:+UseG1GC等参数用于选择不同的垃圾收集器,不同的垃圾收集器对堆大小的设置有不同的要求。比如-XX:+UseSerialGC、-XX:+UseG1GC
为什么堆的空间不连续
由于堆内存的分配和释放是动态的,其空间的分布是不规则的,因此堆的空间是不连续的。 当程序向堆中申请内存时,堆可能会在已分配的内存块之间留下一些未使用的“碎片”,这些碎片可能太小,无法满足程序对更大内存块的申请。 这就是堆内存碎片问题,它可能会导致堆空间的利用效率下降。 总之,堆空间是不连续的,它的分配和释放是动态的,可能会产生内存碎片问题 因此hashMap扩容要重新创建哈希表,采用复制算法,因为Entry类型的hashTable数组必须是连续的(不然直接向后添加可能后面没有连续空间了)