本文参考引用,本人整理个人理解。地址点击

1.实现原理

synchronized可以保证方法或者代码块在运行时,同一时刻只有一个方法可以进入到临界区,同时它还可以保证共享变量的内存可见性。

下面是一些同步的基础

  1. 普通同步方法,锁是当前实例对象;
  2. 静态同步方法,锁是当前类的class对象;
  3. 同步方法块,锁是括号里面的对象

下面来看看一些代码进行分析

public class SynchronizeTest {

    public synchronized void method1() {
System.out.println(" synchronized method1 ");
} public void method2() {
synchronized (this) {
System.out.println(" synchronized block ");
}
} }

javap解析class文件后如下

 public synchronized void method1();
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String synchronized method1
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return public void method2();
Code:
0: aload_0
1: dup
2: astore_1
3: monitorenter // 获取锁
4: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
7: ldc #5 // String synchronized block
9: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
12: aload_1
13: monitorexit // 释放锁
14: goto 22
17: astore_2
18: aload_1
19: monitorexit // 异常情况等也需要释放锁
20: aload_2
21: athrow
22: return

上面可以看出method2的code的3和13分别对应synchronize监视器的进入获取锁和退出释放锁。

说明:同步代码块是使用monitorenter和monitorexit指令实现的,同步方法(在这看不出来需要看JVM底层实现)依靠的是方法修饰符上的ACCSYNCHRONIZED实现。

  • 同步代码块

    monitorenter指令插入到同步代码块的开始位置,monitorexit指令插入到同步代码块的结束位置,JVM需要保证每一个monitorenter都有一个monitorexit与之相对应。任何对象都有一个monitor与之相关联,当且一个monitor被持有之后,他将处于锁定状态。线程执行到monitorenter指令时,将会尝试获取对象所对应的monitor所有权,即尝试获取对象的锁;

  • 同步方法

    synchronized方法则会被翻译成普通的方法调用和返回指令如:invokevirtual、areturn指令,在VM字节码层面并没有任何特别的指令来实现被synchronized修饰的方法,而是在Class文件的方法表中将该方法的accessflags字段中的synchronized标志位置1,表示该方法是同步方法并使用调用该方法的对象或该方法所属的Class在JVM的内部对象表示Klass做为锁对象。

    (摘自:http://www.cnblogs.com/javaminer/p/3889023.html)

2.对象头

HotSpot虚拟机中,对象在内存中的布局分为三块区域:对象头、实例数据和对齐填充。其中对象头包括两部分:Mark Word 和 类型指针。

Mark Word

用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等等,占用内存大小与虚拟机位长一致。Java对象头一般占有两个机器码(在32位虚拟机中,1个机器码等于4字节,也就是32bit),另外,如果对象是一个Java数组,那在对象头中还必须有一块用于记录数组长度的数据,因为虚拟机可以通过普通Java对象的元数据信息确定Java对象的大小,但是从数组的元数据中无法确定数组的大小。

类型指针

对象指向它的类的元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。并不是所有的虚拟机实现都必须在对象数据上保留类型指针,换句话说查找对象的元数据信息并不一定要经过对象本身。

其中锁标示位就是我们需要关注的

3、Monitor

什么是Monitor?


我们可以把它理解为一个同步工具,也可以描述为一种同步机制,它通常被描述为一个对象。 与一切皆对象一样,所有的Java对象是天生的Monitor,每一个Java对象都有成为Monitor的潜质,因为在Java的设计中 ,每一个Java对象自打娘胎里出来就带了一把看不见的锁,它叫做内部锁或者Monitor锁。 Monitor 是线程私有的数据结构,每一个线程都有一个可用monitor record列表,同时还有一个全局的可用列表。每一个被锁住的对象都会和一个monitor关联(对象头的MarkWord中的LockWord指向monitor的起始地址),同时monitor中有一个Owner字段存放拥有该锁的线程的唯一标识,表示该锁被这个线程占用。

Monitor 是线程私有的数据结构,每一个线程都有一个可用monitor record列表,同时还有一个全局的可用列表。每一个被锁住的对象都会和一个monitor关联(对象头的MarkWord中的LockWord指向monitor的起始地址),同时monitor中有一个Owner字段存放拥有该锁的线程的唯一标识,表示该锁被这个线程占用。

其结构如下:

  • Owner:初始时为NULL表示当前没有任何线程拥有该monitor record,当线程成功拥有该锁后保存线程唯一标识,当锁被释放时又设置为NULL。

  • EntryQ:关联一个系统互斥锁(semaphore),阻塞所有试图锁住monitor record失败的线程。

  • RcThis:表示blocked或waiting在该monitor record上的所有线程的个数。

  • Nest:用来实现重入锁的计数。HashCode:保存从对象头拷贝过来的HashCode值(可能还包含GC age)。

  • Candidate:用来避免不必要的阻塞或等待线程唤醒,因为每一次只有一个线程能够成功拥有锁,如果每次前一个释放锁的线程唤醒所有正在阻塞或等待的线程,会引起不必要的上下文切换(从阻塞到就绪然后因为竞争锁失败又被阻塞)从而导致性能严重下降。

    Candidate只有两种可能的值0表示没有需要唤醒的线程1表示要唤醒一个继任线程来竞争锁。

摘自:Java中synchronized的实现原理与应用

4.锁优化

java se 1.6以后对synchronize进行了优化。使其看起来没那么重

深入理解synchronize的更多相关文章

  1. 《深入理解Java内存模型》读书总结

    概要 文章是<深入理解Java内容模型>读书笔记,该书总共包括了3部分的知识. 第1部分,基本概念 包括"并发.同步.主内存.本地内存.重排序.内存屏障.happens befo ...

  2. 理解ThreadLocal(之一)

    ThreadLocal是什么 在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路.使用这个工具类可以很简洁地编 ...

  3. 简单理解Socket

    题外话 前几天和朋友聊天,朋友问我怎么最近不写博客了,一个是因为最近在忙着公司使用的一些控件的开发,浏览器兼容性搞死人:但主要是因为这段时间一直在看html5的东西,看到web socket时觉得很有 ...

  4. [转]简单理解Socket

    简单理解Socket 转自 http://www.cnblogs.com/dolphinX/p/3460545.html  题外话 前几天和朋友聊天,朋友问我怎么最近不写博客了,一个是因为最近在忙着公 ...

  5. wait() notify()搭配synchronize的使用

    一直以为自己动多线程,使用过好像就懂了原理一样,其实是按部就班的写自己不知道原理的代码而已. 一些概念: 监视器:将监视器比作一个建筑,建筑里面有个特别的房间,房间中有一些数据,这些数据在同一个时间只 ...

  6. 对Java内存模型即JMM的理解

    类似物理上的计算机系统,Java虚拟机规范中也定义了一种Java内存模型,即Java Memory Model(JMM),来屏蔽掉各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能 ...

  7. socket,TCP/IP的理解

    TCP/IP 要想理解socket首先得熟悉一下TCP/IP协议族, TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间 ...

  8. 彻底理解ThreadLocal

    ThreadLocal是什么 早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路.使用这个工具类可以很简洁地 ...

  9. 【转】 简单理解Socket

    题外话 前几天和朋友聊天,朋友问我怎么最近不写博客了,一个是因为最近在忙着公司使用的一些控件的开发,浏览器兼容性搞死人:但主要是因为这段时间一直在看html5的东西,看到web socket时觉得很有 ...

随机推荐

  1. python 爬糗事百科

    糗事百科网站段子爬取,糗事百科是我见过的最简单的网站了!!! #-*-coding:utf8-*- import requests import re import sys reload(sys) s ...

  2. HDU(3560)成环,并查集

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3560 并查集查有几个块,修改了之前我的一个方法(用什么map),直接判断根节点的id是i的个数. 然后 ...

  3. halcon保存带有region的图片算子

    显示带区域的图片除了可以用dev_display挨个显示外再截图,还可以通过一个算子来实现这一功能 这个算子是:dump_window_image.(其实就是截图) 这个算子的意思是把WindowHa ...

  4. [转]C++ explicit的作用

    explicit作用: 在C++中,explicit关键字用来修饰类的构造函数,被修饰的构造函数的类,不能发生相应的隐式类型转换,只能以显示的方式进行类型转换. explicit使用注意事项: * e ...

  5. BZOJ2005: [Noi2010]能量采集(容斥原理 莫比乌斯反演)

    Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 4727  Solved: 2877[Submit][Status][Discuss] Descript ...

  6. Exception occurred during processing request: The given object has a null identifier: com.zsn.crm.Model.SaleVisit; nested exception is org.hibernate.TransientObjectException: The given object has a nu

    edit.jsp页面没有加入隐藏字段 id ,导致模型驱动封装时缺少id ,,调用update更新数据库时出错!

  7. 安装破解IDEA(个人使用)

    安装的过程,许多的教程都会有,我在这里附上一两个链接吧:https://blog.csdn.net/newabcc/article/details/80601933 他这里也有破解过程,但是比较麻烦, ...

  8. 10.2 DOM 操作技术【JavaScript高级程序设计第三版】

    很多时候,DOM 操作都比较简明,因此用JavaScript 生成那些通常原本是用HTML 代码生成的内容并不麻烦.不过,也有一些时候,操作DOM 并不像表面上看起来那么简单.由于浏览器中充斥着隐藏的 ...

  9. 数据分析处理库Pandas——对象操作

    Series结构 索引 修改 旧数据赋值给新数据,旧数据不变. 对某一数值进行修改,可以选择保留修改前或修改后的数值. 替换索引 修改某一个索引 添加 在数据1后添加数据2,数据1不改变. 添加一个数 ...

  10. opencv 图像的线性混合

    1 线性混合理论 g(x) = (1-α)*f1(x) + α*f2(x) 其中,α代表图像的权重 #include<iostream> #include<opencv2/openc ...