java学习资料

1.事务失效场景

大概列举几种情况,仅供参考;
1. 直接new出来的对象添加事务不起作用,因为只有spring定义的bean才接受事务。
2.由于mysql的引擎用Myisam不支持事务,所以如果使用mysql的myisam引擎的话,事务不起作用。
3.如果@Transaction注解到非public方法上,事务不起作用,这是因为spring的Aop特性。
4.如果在当前类中进行内部调用方法,比如在A类中有a方法和b方法,a方法没有加@Transaction,b方法加了@Transaction,在方法a中调用方法b,方法b中的事务也不会生效。这是因为spring在扫描bean的时候会自动为标注了@Transaction注解类生成一个代理类,在有注解方法被调用时,实际上是代理类调用的,代理类在调用之前会开启事务,执行事务操作。但是同类中的方法相互调用,相当于this.b(),此时的b方法并非代理类调用,而是直接通过原有的bean直接调用,所以注解不起作用。
5.异常类型错误,如果抛出的runtimeException事务才会回滚。
6.如果异常被catch到,必须要抛出异常,事务才会回滚。

2.synchronized 和 volatile区别

synchronized 和 volatile 都是 Java 中用于实现线程同步和内存可见性的关键字。它们之间的主要区别在于如何使用以及它们提供的同步功能。

1. 目的:
synchronized:它主要用于实现线程同步,确保在同一时刻只有一个线程可以访问共享资源,从而防止数据竞争和保证数据的完整性。

volatile:它主要用于确保变量的可见性。当一个线程修改了一个被 volatile 修饰的变量,修改的值会立即同步到主内存,其他线程可以立即看到最新的值。这样可以防止线程在本地缓存中使用过期的值。

2. 用法:
synchronized:可以作用于方法或代码块。当它作用于方法时,整个方法都是同步的;当它作用于代码块时,只有在该代码块内的操作是同步的。

volatile:仅作用于变量。通过将变量声明为 volatile,可以确保其在多线程环境下的可见性。

3. 原子性:
synchronized:可以保证代码块或方法内的操作是原子的,即不可中断和分割。在同步代码块或方法内的多个操作是连续执行的,不会被其他线程插入。

volatile:仅保证单个读/写操作的原子性,不能保证复合操作(例如自增)的原子性。

4. 性能:
synchronized:由于需要获取和释放锁,性能开销较大,可能导致线程阻塞。

volatile:性能开销较小,因为它仅通过内存屏障来保证变量的可见性,不涉及锁的操作。
总结
在实际开发中,根据具体的应用场景和需求选择使用 
synchronized 或 volatile。

如果需要确保代码块或方法的原子性和互斥访问,应使用 synchronized;

如果仅需要确保变量的可见性,而不需要保证复合操作的原子性,可以使用 volatile。

3.索引失效场景

1. 在索引列上进行运算操作,索引将失效。
2. 字符串类型字段使用时,不加引号,索引将失效。
3. 模糊查询中,如果仅仅是尾部模糊匹配,索引不会是失效;如果是头部模糊匹配,索引失效。
4. 用 or 分割开的条件,如果 or 其中一个条件的列没有索引,那么涉及的索引都不会被用到。
5. 如果 MySQL 评估使用索引比全表更慢,则不使用索引。
6. 若是联合索引,如果不遵循最左前缀原则,也会导致索引失效。

4.srping解决循环依赖:

这三级缓存分别指:
singletonObjects:单例对象的cache
earlySingletonObjects :提前暴光的单例对象的Cache
singletonFactories : 单例对象工厂的cache
Spring首先从一级缓存singletonObjects中获取。如果获取不到,并且对象正在创建中,就再从二级缓存earlySingletonObjects中获取。如果还是获取不到且允许singletonFactories通过getObject()获取,就从三级缓存singletonFactory.getObject()(三级缓存)获取,如果获取到了则:
从singletonFactories中移除,并放入earlySingletonObjects中。其实也就是从三级缓存移动到了二级缓存。

为什么需要三级缓存:【有料】Spring Bean 循环依赖为什么需要三级缓存_daobuxinzi的博客-CSDN博客

5.spring初始化bean的过程

1>首先尝试从一级缓存中获取serviceA实例,发现不存在并且serviceA不在创建过程中;
2>serviceA完成了初始化的第一步(实例化:调用createBeanInstance方法,即调用默认构造方法实例化);
3>将自己(serviceA)提前曝光到singletonFactories中;
4>此时进行初始化的第二步(注入属性serviceB),发现自己依赖对象serviceB,此时就尝试去get(B),发现B还没有被实create,所以走create流程;
5>serviceB完成了初始化的第一步(实例化:调用createBeanInstance方法,即调用默认构造方法实例化);
6>将自己(serviceB)提前曝光到singletonFactories中;
7>此时进行初始化的第二步(注入属性serviceA);
8>于是尝试get(A),尝试一级缓存singletonObjects(肯定没有,因为A还没初始化完全),尝试二级缓存earlySingletonObjects(也没有),尝试三级缓存singletonFactories,由于A通过ObjectFactory将自己提前曝光了,所以B能够通过ObjectFactory.getObject拿到A对象(虽然A还没有初始化完全,但是总比没有好呀);
9>B拿到A对象后顺利完成了初始化阶段1、2、3,完全初始化之后将自己放入到一级缓存singletonObjects中;
10>此时返回A中,A此时能拿到B的对象顺利完成自己的初始化阶段2、3,最终A也完成了初始化,进去了一级缓存singletonObjects中;

6.MVCC

多版本并发控制
readview:四大核心参数
当前最小事务ID
当前最大的已提交事务ID
当前活跃的事务列表
当前的事务ID
通过和undolog的事务版本链进行对比选择需要读取的数据


7.Redis分布式锁实现

setnx命令:表示SET if Not eXists,即如果 key 不存在,才会设置它的值,否则什么也不做
锁的释放
当客户端1操作完后,释放锁资源,即删除try_lock。那么此时客户端2再次尝试获取锁时,则会获取锁成功。
可重入锁。
先判断如果锁名不存在,则加锁。接下来,判断如果锁名和 线程ID,如value=线程ID则可重入操作
请问你用 Redis 做分布式锁的时候,如果指定过期时间到了,把锁给释放了。但是任务还未执行完成,导致任务再次被执行,这种情况你会怎么处理呢
分布式锁问题:用redisson框架,可以api多,看门狗机制(Redisson提供的分布式锁是支持锁自动续期的,也就是说,如果线程仍旧没有执行完,那么redisson会自动给redis中的目标key延长超时时间(1/3),这在Redisson中称之为 Watch Dog 机制。)


8.CAS

CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。 如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值 。否则,处理器不做任何操作。
CAS的优点
利用CPU的CAS指令,同时借助JNI来完成Java的非阻塞算法。其它原子操作都是利用类似的特性完成的。而整个J.U.C都是建立在CAS之上的,因此对于synchronized阻塞算法,J.U.C在性能上有了很大的提升。
CAS存在的三大问题
1.ABA问题  2.循环时间长开销大   3.只能保证一个共享变量的原子操作

利用版本号比较可以有效解决ABA问题。

https://www.cnblogs.com/shoshana-kong/p/10833837.html


9.AQS 原理

1.AQS内部维护了一个int类型的变量state,用户表示加锁的状态。初始值为0,表示没有加锁
2.还维护一个关键变量,用来表示当前加锁的线程,初始值为null
3.如果此时有线程1过来加锁(比如调用实现类ReentrantLock的lock()方法尝试加锁),就会用CAS操作将state值从0改为1,如果修改成功,再把加锁线程设为自己。
 4.如果此时,线程2过来加锁,会发现state不是0,再判断锁线程是否是自己(如果是,
直接将state加1),发现不是,所以此时线程2就会加锁失败。接着,线程2会
将自己加入AQS内部的一个等待队列,进行排队,等待线程1释放锁。
5.当线程1执行完操作,释放了锁(将state减一,如果是0,则彻底释放锁,将“加锁线程“设为null),然后,会从等待队列对头唤醒线程2重新获取锁。
6.线程2重新尝试获取锁,此时执行CAS操作,将state置为1,将加锁线程改为自己,同时线程2从等待队列中出队。

https://www.cnblogs.com/ericz2j/p/13445822.html

10.bean的存储

bean对象最终存储在spring容器中,我们简单的、狭义上的spring容器,在spring源码底层就是一个map集合,这个map集合存储的key是当前bean的name,如果不指定,默认的是class类型首字母小写作为key,value是bean对象。存储bean的map在
当Spring容器扫描到Bean类时 , 会把这个类的描述信息, 以包名加类名的方式存到beanDefinitionMap 中,
Map<String,BeanDefinition> , 其中 String是Key , 默认是类名首字母小写 , BeanDefinition , 存的是类的定义(描述信息) , 我们通常叫BeanDefinition接口为 : bean的定义对象。
1.spring在将class文件转换为beanDefinition的时候,是没有额外的要求的,不管这个bean是单例的,还是原型的,还是懒加载的,都会扫描出来,统一放到beanDefinitionMap集合中。
2.在第二步去初始化bean的时候,才会判断当前bean是否是原型的、是否是懒加载的、是否是有依赖关系的,等
三级缓存的应用时机
Bean对象在被实例化后会放入第三级缓存(addSingletonFactory)
二级缓存的应用时机
在Bean对象被放入三级缓存后,以后的操作如果要进入缓存查询,就会将
三级缓存中的Bean对象移动到二级缓存**,此时放在三级缓存的Bean对象会被移除
一级缓存的应用时机
在Bean对象创建完毕后会放入一级缓存。(addSingleton)
在要用到一个Bean对象之前,都会尝试从缓存中获取,最先就是判断一级缓存中存不存在,所以称“一级”。

11.Zookeeper集群中节点之间数据同步

1.⾸先集群启动时,会先进⾏领导者选举,确定 哪个节点是Leader ,哪些节点是 Follower 和 Observer
2.然后Leader会和其他节点进⾏ 数据同步 ,采⽤ 发送快照 和 发送Diff⽇志 的⽅式
3.集群在⼯作过程中,所有的写请求都会交给Leader节点来进⾏处理,从节点只能处理读请求
4.Leader节点收到⼀个写请求时,会通过 两阶段机制 来处理
5.Leader节点会将该写请求对应的⽇志发送给其他Follower节点并等待Follower节点持久化⽇志成功
6.Follower节点收到⽇志后会进⾏持久化,如果持久化成功则发送⼀个Ack给Leader节点
7.当Leader节点收到半数以上的 Ack 后,就会开始提交,先更新Leader节点本地的内存数据
8.然后发送 commit 命令给 Follower 节点,Follower节点收到commit命令后就会 更新各⾃本地内存数据
9.同时Leader节点还是将当前写请求直接发送给Observer节点,Observer节点收到Leader发过来的写请求后直接执⾏更新本地内存数据
10.最后Leader节点返回客户端写请求响应成功
11.通过 同步机制 和 两阶段提交机制 来达到 集群中节点数据⼀致

zk选举
服务刚起时:
ZAB选举中的每个节点都记录三个元素,节点ID、事务ID、选举轮数,投票信息包括节点ID(被选举节点)、事务ID(投票节点具有的)。
选举原则:事务ID最大当选,事务ID一致则节点ID最大的当选。

服务启动后:启动后先对比选举轮数后对比事物ID再节点ID(轮数最大其实事物ID也是最大)

ZAB选举涉及四种状态:
选举状态,选举过程中所有节点的状态,观察者节点除外
领导状态,领导节点的状态,领导节点可以向其他节点广播合同步信息。
跟随状态,非领导节点的状态
观察状态,观察者具有的状态,无投票合选举权
选举流程
ZAB选举中的每个节点都记录三个元素,节点ID、事务ID、选举轮数,投票信息包括节点ID(被选举节点)、事务ID(投票节点具有的)。
选举原则:事务ID最大当选,事务ID一致则节点ID最大的当选。

12.GC root对象是什么?

Java中可以作为GC Roots的对象
1、虚拟机栈(javaStack)(栈帧中的局部变量区,也叫做局部变量表)中引用的对象。
2、方法区中的类静态属性引用的对象。
3、方法区中常量引用的对象。
4、本地方法栈中JNI(Native方法)引用的对象。

  • 16
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值