背景
最近做一个报表,基础数据比较大,然后开了3个线程处理,然后分别向Map里面里面插入数据,这个的Map用的是HashMap,所以为了避免多线程安全性问题。需要在HashMap添加数据的地方要加一个锁。那么有人来说了,你可以用线程安全的CurrentHashMap啊,那你有没有思考过在多线程的环境下CurrentHashMap所有的操作都是安全的吗?这里对CurrentHashMap安不安全先不展开讨论。因为要用到锁,所以绕不过去的肯定就synchronized和ReentrantLock。那这两中锁从实现的方式上有什么不同呢,我们一起来了解一下。
首先来先看synchronized,毕竟使用起来简单嘛哈哈哈哈哈,因为synchronized是jvm里面的一个关键字,所以如果你想通过常规的查看源码的方式来弄明白synchronized估计就不行了。所以我们只能通过jdk自带的工具javap -c [class文件] 来通过字节码分析。
先放上测试代码和他对应的字节码。
1 public void method1() { 2 synchronized (this) 3 { 4 5 } 6 }
相对于普通方法,我们是不是一眼就可以看出有差别的地方了,那就是在code:5和code:10那里。根据JVM规范要求,当在执行在执行monitorenter指令的时候,首先要去尝试获取对象的锁,如果这个对象没有被锁定,或者当前线程已经拥有了这个对象的锁,就把锁的计数器加1,相应地,在执行monitorexit的时候会把计数器减1,当计数器减小为0时,锁就释放了。
通过字节码我们可以知道synchronized锁执行过程,那他底层是怎么来实现的呢?首先在jvm规范中任何一个对象都由三部分组成的,对象头,数据,填充位。在对象头中又分为两部分,第一部分主要用于储存对象自身的运行时数据,比如hashCode,GC年龄,锁信息等。
对象头的另外一部分是类型执指针,即对象指向他的类元数据的指针。