经验分享:究竟大厂面试官爱招什么样的人?+Java锁技术干货分享

点赞关注,不会迷路!   

前言

前天有朋友跟我吐槽了工作上的事,征得他同意之后,下面用第一人称展示给大家

好不容易约来了一名程序员来面试,这位程序员有三年工作经验,期望薪资10k。我看这位求职者各方面还挺不错的。
在程序员这行业,三年工作经验,又是一线城市,人家期望薪资也不高。

于是我很高兴地跟领导说,“怎么样,这次应该满意了吧。”

谁知领导说,这位求职者对多线程,线程池,属性动画这些技术要点不熟悉。

虽然他这三年里做了好多项目,但大都是类似的,普遍都是一些增删改查的功能,项目没什么特色,项目核心技术较少,其技术含量实际相当一年工作经验的水平。
不给录用。

好晕,又得去约人来面试了。
这个岗位已经招了半个月了,还是没有招到,可领导隔三差五来要人,结果来了又说不合适,这要求也太高了吧。

心累!

像我们IT打工人 项目经历和核心技术比工作年限重要。一直做crud菜鸟,核心技术得不到提升,年纪越大跳槽越难。编程是个需要不断更新知识库的行业。文末有福利,帮你搜集行业最新技术消息

今天给大家介绍一个能帮你解决90%以上Java面试中的锁问题(Java中的锁)

java头的信息分析

首先为什么我要去研究java的对象头呢?
这里截取一张hotspot的源码当中的注释
并发锁
这张图换成人可读的表格如下并发编程

意思是java的对象头在对象的不同状态下会有不同的表现形式,主要有三种 状态,无锁状态、加锁状态、gc标记状态。那么我可以理解java当中的取锁其实 可以理解是给对象上锁,也就是改变对象头的状态,如果上锁成功则进入同步代码块。但是java当中的锁有分为很多种,从上图可以看出大体分为偏向锁、轻量 锁、重量锁三种锁状态。这三种锁的效率完全不同、关于效率的分析会在下文分 析,我们只有合理的设计代码,才能合理的利用锁、那么这三种锁的原理是什么?所以我们需要先研究这个对象头。

java对象的布局以及对象头的布局

1、JOL来分析java的对象布局

1 首先添加JOL的依赖
 2 <dependency>
  3 <groupId>org.openjdk.jol</groupId> 
  4 <artifactId>jol‐core</artifactId>
5 <version>0.9</version>
 6 </dependency>

A.java

1 public class A { 
2 //没有任何字段 
3 }

JOLExample1.java

1 package com.luban.layout; 
2 import org.openjdk.jol.info.ClassLayout; 
3 import org.openjdk.jol.vm.VM; 
4 import static java.lang.System.out; 
5
6 public class JOLExample1 {
7 public static void main(String[] args) throws Exception { 
8 out.println(VM.current().details()); 
9 out.println(ClassLayout.parseClass(A.class).toPrintable()); 
10 } 
11 }

运行结果

1 # Running 64‐bit HotSpot VM. 
2 # Using compressed oop with 0‐bit shift. 
3 # Using compressed klass with 3‐bit shift. 
4 # Objects are 8 bytes aligned. 
5 # Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] 
6 # Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] 
7
8 com.luban.layout.A object internals: 
9 OFFSET SIZE TYPE DESCRIPTION VALUE 
10 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 
11 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
12 8 4 (object header) 82 22 01 20 (10000010 00100010 00000001 00100000) (536945282) 
13 12 4 (loss due to the next object alignment) 
14 Instance size: 16 bytes 
15 Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

分析结果1

1 Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]对应:[Oop(Ordinary Object Pointer), boolean, byte, char, short, int, float, long, double]大小

整个对象一共16B,其中对象头(Object header)12B,还有4B是对齐的 字节(因为在64位虚拟机上对象的大小必须是8的倍数),由于这个对象里面没有 任何字段,故而对象的实例数据为0B?两个问题

  • 1、什么叫做对象的实例数据呢?

  • 2、那么对象头里面的12B到底存的是什么呢?

首先要明白什么对象的实例数据很简单,我们可以在A当中添加一个 boolean的字段,大家都知道boolean字段占1B,然后再看结果
A.java

1 public class A {
 2 //占一个字节的boolean字段 
 3 boolean flag =false; 
 4 }

运行结果2

1 # Running 64‐bit HotSpot VM. 
2 # Using compressed oop with 0‐bit shift. 
3 # Using compressed klass with 3‐bit shift. 
4 # Objects are 8 bytes aligned. 
5 # Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] 
6 # Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] 
7
8 com.luban.layout.A object internals: 
9 OFFSET SIZE TYPE DESCRIPTION VALUE 
10 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
11 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
12 8 4 (object header) 82 22 01 20 (10000010 00100010 00000001 00100000) (536945282) 
13 12 1 boolean A.flag false 
14 13 3 (loss due to the next object alignment) 
15 Instance size: 16 bytes 
16 Space losses: 0 bytes internal + 3 bytes external = 3 bytes total

分析结果2

整个对象的大小还是没有改变一共16B,其中对象头(Object header)12B, boolean字段flag(对象的实例数据)占1B、剩下的3B就是对齐字节。由此我 们可以认为一个对象的布局大体分为三个部分分别是对象头(Object header)、对象的实例数据字节对齐

接下来讨论第二个问题,对象头为什么是12B?这个12B当中分别存储的是什么 呢?(不同位数的VM对象头的长度不一样,这里指的是64bit的vm) 关于java对象头的一些专业术语

http://openjdk.java.net/groups/hotspot/docs/HotSpotGlossary.html
首先引用openjdk文档当中对对象头的解释

object header Common structure at the beginning of every GC-managed heap object. (Every oop points to an object header.) Includes fundamental information about the heap object’s layout, type, GC state, synchronization state, and identity hash code. Consists of two words. In arrays it is immediately followed by a length field. Note that both Java objects and VM- internal objects have a common object header format

上述引用中提到一个java对象头包含了2个word,并且好包含了堆对象的布 局、类型、GC状态、同步状态和标识哈希码,具体怎么包含的呢?又是哪两个 word呢?

mark word The first word of every object header. Usually a set of bitfields including synchronization state and identity hash code. May also be a pointer (with characteristic low bit encoding) to synchronization related information. During GC, may contain GC state bits.

mark word为第一个word根据文档可以知他里面包含了锁的信息, hashcode,gc信息等等,第二个word是什么呢?

klass pointer The second word of every object header. Points to another object (a metaobject) which describes the layout and behavior of the original object. For Java objects, the “klass” contains a C++ style “vtable”.

klass word为对象头的第二个word主要指向对象的元数据。
在这里插入图片描述
假设我们理解一个对象头主要上图两部分组成(数组对象除外,数组对 象的对象头还包含一个数组长度),那么一个java的对象头多大呢?我们从JVM 的源码注释中得知到一个mark word一个是64bit,那么klass的长度是多少呢?

所以我们需要想办法来获得java对象头的详细信息,验证一下他的大小,验 证一下里面包含的信息是否正确。

根据上述利用JOL打印的对象头信息可以知道一个对象头是12B,其中8B是 mark word 那么剩下的4B就是klass word了,和锁相关的就是mark word了, 那么接下来重点分析mark word里面信息

在无锁的情况下markword当中的前56bit存的是对象的hashcode,那么来 验证一下

java代码和运行结果:

1 public static void main(String[] args) throws Exception { 
2 A a= new A(); 
3 out.println("befor hash"); 
4 //没有计算HASHCODE之前的对象头 
5 out.println(ClassLayout.parseInstance(a).toPrintable()); 
6 //JVM 计算的hashcode 
7 out.println("jvm‐‐‐‐‐‐‐‐‐‐‐‐"+Integer.toHexString(a.hashCode())); 
8 HashUtil.countHash(a); 
9 //当计算完hashcode之后,我们可以查看对象头的信息变化 
10 out.println("after hash"); 
11 out.println(ClassLayout.parseInstance(a).toPrintable()); 
12
13 }
1 befor hash 
2 com.luban.layout.A object internals: 
3 OFFSET SIZE TYPE DESCRIPTION VALUE 
4 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 
5 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
6 8 4 (object header) 43 c1 00 20 (01000011 11000001 00000000 00100000) (5 36920387) 
7 12 1 boolean A.flag false 
8 13 3 (loss due to the next object alignment) 
9 Instance size: 16 bytes 
10 Space losses: 0 bytes internal + 3 bytes external = 3 bytes total 
11
12 jvm‐‐‐‐‐‐‐‐‐‐‐‐0x6ae40994 
13 util‐‐‐‐‐‐‐‐‐‐‐0x6ae40994 
14 after hash 
15 com.luban.layout.A object internals: 
16 OFFSET SIZE TYPE DESCRIPTION VALUE 
17 0 4 (object header) 01 94 09 e4 (00000001 10010100 00001001 11100100) (‐469134335) 
18 4 4 (object header) 6a 00 00 00 (01101010 00000000 00000000 00000000) (106) 
19 8 4 (object header) 43 c1 00 20 (01000011 11000001 00000000 00100000) (536920387) 
20 12 1 boolean A.flag false 
21 13 3 (loss due to the next object alignment) 
22 Instance size: 16 bytes 
23 Space losses: 0 bytes internal + 3 bytes external = 3 bytes total 
24
25
26 Process finished with exit code 0

http://tool.oschina.net/hexconvert/ 进制转换

1 package com.luban.layout; 
2 import sun.misc.Unsafe; 
3 import java.lang.reflect.Field; 
4
5 public class HashUtil { 
6 public static void countHash(Object object) throws NoSuchFieldException, IllegalAccessException { 
7 // 手动计算HashCode 
8 Field field = Unsafe.class.getDeclaredField("theUnsafe"); 
9 field.setAccessible(true); 
10 Unsafe unsafe = (Unsafe) field.get(null); 
11 long hashCode = 0; 
12 for (long index = 7; index > 0; index‐‐) { 
13 // 取Mark Word中的每一个Byte进行计算 
14 hashCode |= (unsafe.getByte(object, index) & 0xFF) << ((index ‐ 1) * 8);
15 } 
16 String code = Long.toHexString(hashCode); 
17 System.out.println("util‐‐‐‐‐‐‐‐‐‐‐0x"+code); 
18
19 } 
20 }

由于篇幅问题,分析结果3和4 下期更新

最后

今天的内容就到这里了,希望对大家有帮助。

就面试而言很多知识其实我们可以很容易就掌握了,但是要以学习为目的,你会发现很多东西我们得深入到计算机基础上才能发现其中奥秘。

最后还想对你们说几句心里话,工作这么多年,也帮别人面试过一些人。不管是站在面试官的角度看还是leader的视角,面试大厂除了面试技巧和经验,过硬的技术和好的项目经验也是自己的王牌和底气。一线大厂核心技术分享

 我花了比较长的时间整理了一些学习资料,上面发的就是资料中的冰山一角,希望能帮到大家!点击一起学习 暗号:csdn

                         

  后续会分享更多纯干货文章,希望能真正帮到你们。你们的支持就是我最大的动力!欢迎关注点赞啊!

                                                       

猜你喜欢

转载自blog.csdn.net/weixin_50333534/article/details/109265528