从violate到ConcurrentHashMap,我通过引导面试官,过了多场技术面试

这应该是2,3年前的事情了,不过本文给出的技巧比较有通用型,一些Java开发经验在3年以内,甚至是5年以内的程序员,在面试时,都可以采用类似的技巧在面试中高效展示实力。

我们知道面试官喜欢问多线程问题,尤其在面初级开发的时候更会问,而在问多线程问题时,又会经常会问violate关键字。

我们知道violate关键字本身有三大方面的说辞。

1 能防止指令重排。

2 能确保线程内存中的对象和主线程内对象同步,即确保线程内存中对象对其他线程的可见性。

3 violate关键字不能当锁用,即在一个线程对象里某变量用该关键字修饰,在多线程的都访问该对象时,不能确保该对象的线程安全。

但是当时我说好这些说辞,又多说了一句,我看过ConcurrentHashMap底层源码,在其中用到了violate关键字。我怕面试官不让我继续展开说明,我又加了一句,我能否结合ConcurrentHashMap底层源码说明violate关键字的作用?

说到这份上,面试官估计就不大好意思拒绝了,而且,violate问题是面试官提出来的,我目前是继续用ConcurrentHashMap源码进一步说明这个关键字到含义,不能算我偏题,更不能算我自说自话展示亮点。

然后我继续说出如下的意思。

1 ConcurrentHashMap和HashMap一样,都是以键值对存储数据,只不过ConcurrentHashMap会通过加锁等方式,确保操作时的线程安全。

2 然后去管面试官要纸笔,或者就在白板上写上如下的代码,如果背不出,写个大致也行,反正我当时是背出的。

static final class HashEntry<K,V> {
        final K key;
        final int hash;
        volatile V value;
        final HashEntry<K,V> next;
}

该对象在ConcurrentHashMap里是存储一个键值对,其中用next链表的方式,指向可能产生冲突的元素。其中value被violate修饰,就多个线程同时操作value时,会取最新的value值,这样能确保多个线程访问该ConcurrentHashMap对象时的正确性。

3 同时我再说明,ConcurrentHashMap是分段的(segment),默认是分成16段,ConcurrentHashMap会根据其中每个段的长度,来决定是否要扩容,而每个段里,定义长度的变量也是用violate修饰的。

transient volatile int count;

这样多个线程,就会直接拿到该变量,同时决定是否要扩容。

4 讲到这里,由于在代码里引入了final和transient,那么顺带再解释下,用final修饰的是常量,即定义成不可变对象,这样能确保在多线程并发下,访问这些对象的高效性和安全性。

而transient变量的含义是不参与序列化的过程,即如果要在网上传输对象,对象里的transient变量是不传的,这样能确保对象的安全性,具体在count的场景,就不想再网络传输时传count变量。

我讲到这个份上,由于能全面地展示了Java核心方面的诸多技术要点,包括多线程,final,transient,还有hashmap,有的面试官就不继续问问题了,就让我过技术面试了,大多数的面试官,不会再问我java核心方面的问题了,他们会认为这块我比较熟悉。

但这里,如果面试官还想继续问ConcurrentHashMap的读写线程安全性,我也不怕,我也准备了如下的说辞。

读的话直接读,因为是读,所以不怕多线程并发,不用加锁,但里面会有解决冲突的代码。

V get(Object key, int hash) {
            if (count != 0) { // read-volatile
                HashEntry<K,V> e = getFirst(hash);
                while (e != null) {
                    if (e.hash == hash && key.equals(e.key)) {
                        V v = e.value;
                        if (v != null)
                            return v;
                        return readValueUnderLock(e); // recheck
                    }
                    e = e.next;
                }
            }
            return null;
        }

写的话比较麻烦些,会通过scanAndLockForPut方法,先加锁再写。在面试中,我不必再给出写的具体代码,我只要给出方法名,一般面试官就让我过了,其实这个方法,不少面试官自己都不知道,我都说到这个份上了,甚至比一些面试官懂的还多,这时面试官一般就不会细问了。

要知道,面试不是考试,求职者不用面面俱到说出细节,毕竟写代码时可以参考网络来写,不用什么都自己背。其实求职者真可以大致给出代码,然后给出关键说辞即可。

我就遇到一个面试官,还深入问了写时加锁的情况,我就说,我见了底层代码,但加锁的细节我忘记了,但我知道是通过在scanAndLockForPut方法里加锁,他也就没细问,但此时我也已经成功了展示多线程、数据结构、final和transient等技能了。

我在上文里还提到了hashmap的冲突,相关内容大家可以看我的这篇原创文章。

为什么要重写hashcode和equals方法?初级程序员在面试中很少能说清楚。 - hsm_computer - 博客园我在面试 Java初级开发的时候,经常会问:你有没有重写过hashcode方法?不少候选人直接说没写过。我就想,或许真的没写过,于是就再通过一个问题确认:你在用HashMap的时候,键(Key)部分,https://www.cnblogs.com/JavaArchitect/p/10474448.html其实在上述面试过程中,讲述技能是一方面,另一方面是引导,我从violate引导到了ConcurrentHashMap,并通过源码展示了我的亮点。

其实,如果面试官问到final或transient关键字,你也可以用类似的方法来引导,我也做过类似做法。

我用这套引导话术在面试中取得了哪些成果呢?

1 我去面了两家小公司,说好这套话术后,面试官就直接让我过技术面试了,但当时我去面小公司纯粹是练说辞,所以没去。

2 我去面一家保险公司,不过是外派岗,我用了这套说辞后,Java核心问题没再问,后面问了我spring boot的问题,这套引导说辞能让我成功地证明了java核心方面的技能。

3 我去面一家互联网公司,用了这套说辞后,在java核心方面面试官再问了JVM调优,我用了如下话术也过了。也就是说,通过violate这套说辞,我成功地展示了Java核心方面的技能。

JAVA面试经常会被问题 JVM调优?3 赞同 · 0 评论回答icon-default.png?t=M276https://www.zhihu.com/question/268821097/answer/2394293576

4 我去面了两家外企,用了这套说辞后,面试官直接问我分布式组件的概念了,这套说辞也能很好地让我证明了java核心方面的能力。

大家真可以照此办法,在面试前准备,面试时引导,很能帮助自己过面试,当然在面试前,还需要准备一些衍生问题,比如hashmap的hashcode,equals,hash冲突,final,transient,当然还有ConcurrentHashMap的底层数据结构红黑树和加锁机制,这样就能更好地展示java核心方面的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hsm_computer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值