循环依赖和bean记载过程
Bean加载示例说明
涉及循环依赖和代理的Bean加载
例子:对象A和对象B相互循环依赖,且都有代理。
A实例化;
用对象工厂封装A的实例化对象,将A的工厂对象加入第三级缓存;
A属性注入(需注入属性B),
发现需要先加载B;
B实例化;
用对象工厂封装B的实例化对象,将B的工厂对象加入第三级缓存;
B属性注入(需注入属性A);
通过A的工厂对象得到A代理对象,将A代理对象加入第二级缓存(此时A还是半成品),并从第三级缓
存移除A工厂对象,。
B完成属性注入(注入的是A代理对象);
B初始化,生成B的代理对象;
B代理对象加入第一级缓存,并从第三级缓存移除B工厂对象;
得到B完成品对象(代理对象);
A完成属性注入;
A初始化;
A代理对象加入第一级缓存,并从第二级缓存移除A代理对象;
得到A完成品对象(代理对象)。
乐观锁和悲观锁
乐观锁
每个线程在操作共享资源之前都不会对资源进行加锁,只有在更新资源的时候才会进行冲突检测。乐观锁的实现机制通常是通过版本号和时间戳来追踪共享资源的状态变化。
当一个线程要更新资源时,会获取当前资源的版本号,检查当前版本号是否发生了变化,如果发生变化更新失败,没有发生变化就可以更新成功。乐观锁通常用于读取操作比写入操作频繁的场景
通过版本控制,比如说:
在数据库中有一个version字段和一个余额字段,A、B两个线程要修改余额,分别修改余额后,比如A线程开始提交,提交完后version+1,接下来B线程进行提交的时候,发现version和数据库中的version不一样,就会提交失败
悲观锁
每个线程在操作共享资源之前都会对该资源进行加锁,其他线程无法访问。悲观锁的实现机制通常是加互斥锁,如synchronized关键字。
当一个线程要访问该资源时,会获得该资源的锁,其他线程必须要等该锁释放才能访问资源。
悲观锁通常用于写入操作比读取操作较频繁的场景。
CAS算法
就是用一个预期值和要更新的变量值进行比较,两值相等才会进行更新。
V:要更新的变量值
E:预期值
N: ...
抽象类和接口的区别
抽象类和接口的区别首先明白他们的使用场景?
如果拥有一些方法,想要让它们有默认的具体实现,选择抽象类
如果想要实现多重继承,Java中不支持多继承,但是一个类可以实现多个接口,选择接口
如果有一些基本功能在不断发生变化,选择抽象类,如果使用接口,每次变更都需要去更改实现接口的所有类
抽象类
接口
它可以有默认的方法实现
接口是完全抽象的,不存在方法的实现
子类提供extends关键字来继承抽象类,并且子类不是抽象类的话,需要实现抽象类中声明的方法
子类使用关键字implements来实现接口,需要实现接口中声明的方法
抽象类中的成员变量可以是各种类型的
接口中的成员变量只能是public static final(隐式声明)类型(必须在声明时赋值)
抽象类中可以有静态代码块和静态方法
接口中不能含有静态代码块和静态方法(含有静态变量)
一个类只能继承一个抽象类
一个类可以实现多个接口
抽象方法中可以有public、protected、default这些修饰符
接口方法默认是public abstract
疑问:jdk1.8之后接口有默认的方法( ...
浅谈ConcurrentHashMap
ConcurrentHashMap
首先它是一个线程安全的,它的底层实现是链表+数组+红黑树。
在jdk1.8之前它实现线程安全的方式是:数组+Segment+分段锁实现,其内部分为一个个段数组。Segment通过继承ReentrantLock来进行加锁,通过锁住一个Segment来保证每个Segment内操作的线程安全性,从而实现了全局安全。然后这样做有个缺陷,每次通过hash确认位置时需要两次才能定位当前key落在哪个槽
第一次确认当前key落在哪个Segment数组;第二次确认当前key的具体位置
在jdk1.8之后,它取消了分段锁的设计,使用了CAS+synchronized来实现线程安全的;
想了解更多请参考博客
https://blog.csdn.net/weixin_46574815/article/details/123636105



