最后
看完美团、字节、腾讯这三家的面试问题,是不是感觉问的特别多,可能咱们又得开启面试造火箭、工作拧螺丝的模式去准备下一次的面试了。
开篇有提及我可是足足背下了1000道题目,多少还是有点用的呢,我看了下,上面这些问题大部分都能从我背的题里找到的,所以今天给大家分享一下互联网工程师必备的面试1000题。
注意不论是我说的互联网面试1000题,还是后面提及的算法与数据结构、设计模式以及更多的Java学习笔记等,皆可分享给各位朋友
互联网工程师必备的面试1000题
而且从上面三家来看,算法与数据结构是必备不可少的呀,因此我建议大家可以去刷刷这本左程云大佬著作的《程序员代码面试指南 IT名企算法与数据结构题目最优解》,里面近200道真实出现过的经典代码面试题。
-
- 1. 无锁状态
-
2. 偏向锁
-
3. 轻量级锁
-
4. 重量级锁
-
5. 总结
-
三. 锁优化
-
- 1. 锁消除
-
2. 锁粗化
==================================================================
这部分内容在上篇文章中的 synchronized充当了哪些锁部分已经介绍过了哦,没有看的小伙伴可以去看看synchronized的特性
=============================================================================
在Java中JVM虚拟机将synchronized锁分为无锁、偏向锁、轻量级锁、重量级锁状态。会根据不同的情况,进行不同的升级操作
此状态理解起来较为简单,没有进行线程任务时最开始的状态就是无锁状态。
-
偏向锁类似于一种乐观锁,当一个线程在执行任务时,偏向锁会给这个线程设定一个标记(并不是真正地加锁),如果后续没有其他线程来竞争这个锁,那么这个偏向锁就不会再进行其他的任何操作了,有效避免了因为加锁过程而产生的内存开销问题
-
若有其他线程也竞争这把锁,那么此时第一个线程会立马把锁拿到(因为之前第一个线程已经有了偏向锁标记,所以很容易拿到)然后进入轻量级锁的状态
偏向锁的大体思路是能不加锁就尽量不加锁避免内存开销,只做上标记即可,但如果实在要加锁,也会因为标记的存在而立马把锁拿到(类似于高考填志愿保底心态)
当进入轻量级锁锁状态(自适应自旋锁)后,是完全在用户态上实现的,且是基于CAS来完成的操作,因为这个状态不涉及到内核态和用户态的切换,也不涉及到线程的阻塞和调度过程。所以并不会对系统的内存有着过于高的开销,因此可以保证更高效地获取到锁(一个线程释放锁后,另一个线程会马上获取到锁)
具体步骤
-
通过 CAS 检查并更新一块内存 (比如 null => 该线程引用)
-
如果更新成功, 则认为加锁成功
-
如果更新失败, 则认为锁被占用, 继续自旋式的等待(并不放弃 CPU)
由于自旋操作可能会一直让CPU 空转,比较浪费 CPU 资源,因此此处的自旋不会一直持续进行,而是达到一定的时间(重试)次数,就不再自旋了,也就是所谓的 “自适应”(根据情况来)
当锁的竞争变得非常激烈时,如果再按照之前自旋的方式,那么对于CPU的开销是非常高的,而且此时自旋还不能快速地获取到锁的状态,那么此时就会变成重量级锁(挂起等待锁),对于挂起等待锁来说,锁的等待过程是释放CPU的过程,此时会节省CPU的开销,但付出的代价是引入了线程的阻塞和调度的开销(以CPU资源换取性能)
具体过程
此处的重量级锁就是用到了内核提供的mutex,要执行加锁操作,首先会进入内核态,在内核态判定当前的锁是否已经被占用,若该锁没有被占用,则加锁成功,切换回用户态;若该锁被占用,则加锁失败,此时线程进入锁的等待队列去挂起等待,直到锁被其他线程释放后,操作系统才会唤醒挂起等待锁的这个线程,最后这个线程才会获取到锁
- 锁升级(锁膨胀)的过程完全是
synchronized
内部自适应完成的,即根据不同的情况(即锁冲突的高或低状态)来升级或降级成对应的状态,不需要用户或者程序员去干预,因此使用起来会比较方便。
2.注意, synchronized
在有些JVM版本上是可以同时实现降级和升级的自适应的,但在有些JVM上只能实现升级的自适应。
===================================================================
JVM和编译器提供了一个很好的功能,能判断某段代码是否有加锁的必要(根据情况选择是否需要加锁),以防开发人员加错锁而造成无缘无故开销很大系统内存的情况。
例子
Java提供了两个类,StringBuilder
和StringBuffer
,其中,前者不会考虑线程安全问题,而后者中的每个方法都带有了synchronized
以确保线程安全。但我们平常在单线程下,这个加锁是没有必要的,会白白浪费很多内存资源,这时候,如果开发人员不小心在单线程中使用了StringBuffer
,那么编译器和JVM也会对其进行一定的优化,去把这个锁消除。
注意,编译器的判断也不是每次完全都是正确的,不会每次都会锁消除,因此,还是要提醒大家在写代码过程中自己还是要尽量避免出现此类错误
难道这样就够了吗?不,远远不够!
提前多熟悉阿里往年的面试题肯定是对面试有很大的帮助的,但是作为技术性职业,手里有实打实的技术才是你面对面试官最有用的利器,这是从内在散发出来的自信。
备战阿里时我花的最多的时间就是在学习技术上,占了我所有学习计划中的百分之70,这是一些我学习期间觉得还是很不错的一些学习笔记
我为什么要写这篇文章呢,其实我觉得学习是不能停下脚步的,在网络上和大家一起分享,一起讨论,不单单可以遇到更多一样的人,还可以扩大自己的眼界,学习到更多的技术,我还会在csdn、博客、掘金等网站上分享技术,这也是一种学习的方法。
今天就分享到这里了,谢谢大家的关注,以后会分享更多的干货给大家!
笔记+最新讲解视频+实战项目源码】](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)收录**