写在前面
- 本人目前是北邮非科班大三在读,GPA中上,培养方案内包括一些不是很硬的计算机课程,如C、Java程序开发、Web应用开发、数据库、计算机网络等,讲得比较水,主要靠自学和项目。
- 有过一段京东物流的Java后端实习经历,实习时间比较短,全程跟了两个项目。
- 同期精投了阿里、百度、字节等大厂,没有海投。重点准备了算法、Java SE和MySQL的知识,网络、Spring、Redis准备偏弱。
面试内容
一面:电话面
- 自我介绍
- 面试官口述了一个经典银行扣款场景的Java代码,询问了相关多线程问题:
- Q1:多线程场景下,会出现什么问题?
- A1:举例,现有余额50元,A、B两线程分别计划扣款10和20元。可能出现A线程读取50元后,扣款操作未写入,此时B线程操作执行成功后内存中余额变为30元,而A线程又将40元写入回内存,最终获得不了期望的20元结果。总结来讲是线程的原子性无法被保障。
- Q2:如何解决该问题?
- A2:对方法用synchronized修饰,从而达到加锁的效果。
- Q3:了解volatile关键字吗?volatile关键字修饰余额变量可以吗?
- A3:了解。volatile保证了线程绕过缓存直接读取到关键字所修饰的成员的主存,解决了缓存不一致问题,保障了内存的可见性。在所问场景下,仅用volatile不可以解决该问题,因为volatile仅解决了可见性问题,而该场景下的并发问题主要是操作原子性的问题,不可以用volatile关键字来解决。
- Q4:说回synchronized关键字,synchrinized关键字获取的是谁的锁?
- A4:获取的是对应支付类实例对象的锁,具体的锁描述在JVM堆空间的该对象头部。
- Q5:synchronized关键字还有一种代码块形式,其中圆括号的参数如果是该对象的另一个Object成员,可以吗?
- A5:可以,这样synchronized获取的是指定成员对象的锁,从代码来分析,这个对象在支付类对象的生命周期内唯一,仍然可以有效解决这个问题。
- Q6:这是一个悲观锁还是乐观锁?
- A6:是悲观锁。
- Q7:有没有乐观锁实现手段?
- A7:有两种手段:1. CAS 2. 加入版本号,每次写入时比对版本号,如果与期望不同,则自旋。<