Java并发编程之synchronized关键字
整理一下synchronized关键字相关的知识点。
在多线程并发编程中synchronized扮演着相当重要的角色,synchronized关键字是用来控制线程同步的,可以保证在同一个时刻,只有一个线程可以执行某个方法或者某个代码块,保证一个线程的变化(主要是共享变量的变化)被其他线程所看到,即保证可见性,可以替代volatile。
1、Synchronized具体表现形式
synchronized的实现和对象锁有关,Java中的每一个对象都可以作为锁,具体表现为以下三种形式:
- 修饰普通方法:作用于当前实例加锁,进入同步代码前要获得当前实例的锁;
public synchronized void method1()
{
// todo
}
- 修饰静态方法:作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁;
public static synchronized void method2()
{
// todo
}
- 修饰代码块:指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁。锁是Synchonized括号里配置的对象。配置的对象分为以下三种情况:
1、实例对象
synchronized(this) {
// todo
}
2、类对象
synchronized(Demo.class) {
// todo
}
3、任意实例对象Object
String lock = “”;
synchronized(lock) {
// todo
}
需要注意的是:如果锁的是类对象的话,尽管new多个实例对象,但他们仍然是属于同一个类依然会被锁住,即线程之间保证同步关系。
2、Synchonized实现原理
JVM基于进入和退出Monitor对象来实现方法同步和代码块同步。同步代码块为显示同步,使用monitorenter 和monitorexit指令实现。同步方法为隐式同步,由方法调用指令读取运行时常量池中方法的 ACC_SYNCHRONIZED 标志来隐式实现。
public class SynchronizedDemo {
public static void main(String[] args) {
synchronized (SynchronizedDemo.class) { }
}
public synchronized void method() { }
}
先看下上面这段代码,包含一个同步代码块和一个同步方法。通过javap –v 命令查看编译后的class文件。

先来看下main方法,上图中第4、6、12句命令就是添加synchronized之后生成的。执行同步代码块之前要先执行monitorenter指令,退出和异常的时候执行monitorexit指令。其关键就是必须要对对象的监视器monitor进行获取,当线程获取monitor后才能继续往下执行,否则将会被阻塞在同步块和同步方法的入口处,同时添加到一个同步队列中。每个对象都存在着一个 monitor 与之对应,当 monitor 被线程持有后,它就处于锁定状态,其他线程不能访问。

从上图可以看出,method同步方法没有看到monitorenter和monitorexit指令,而是通过ACC_SYNCHRONIZED标识指明method是一个同步方法。方法调用时,调用指令将会检查方法的 ACC_SYNCHRONIZED 访问标志是否被设置,如果设置了,执行线程将先持有monitor,然后再执行方法,方法完成(无论是正常完成还是非正常完成)时释放monitor。Synchronized先天具有重入性,在同一锁程中,线程不需要再次获取同一把锁。每个对象拥有一个计数器,当线程获取该对象锁后,计数器就会加一,释放锁后就会将计数器减一。
对象,对象监视器,同步队列以及执行线程状态之间的关系如下图:

3、Java对象头
java对象在内存中的布局分为三块区域:对象头、实例数据和对齐填充。如下:
实例变量:存放类的属性数据信息,包括父类的属性信息,如果是数组的实例部分还包括数组的长度,这部分内存按4字节对齐。
填充数据:由于虚拟机要求对象起始地址必须是8字节的整数倍。填充数据不是必须存在的,仅仅是为了字节对齐,这点了解即可。
对象头:synchronized用的锁是存在Java对象头里的,主要结构是Mark Word 和 Class Metadata Address。当对象是数组时,会多一个Array length来存储数组的长度。
- Mark Word里默认存储对象的HashCode、分代年龄和锁标记位。32位JVM的Mark Word默认存储结构如下:

- Class Metadata Address存储了类型指针指向对象的类元数据,JVM通过这个指针确定该对象是哪个类的实例。
对象头的信息与对象自身定义的数据是没有关系的,在运行时,Mark Word里存储的数据会随着锁标志位的变化而变化。除了默认存储结构,还有可能变化成以下结构:
这部分照搬了《Java并发编程的艺术》书中的一段,这块的东西只是简单的过了一遍。
4、synchronized的优化
Java 6中为了减少获得锁和释放锁带来的性能消耗而引入的偏向锁和轻量级锁,以及锁的存储结构和升级过程。锁的状态总共有四种,无锁状态、偏向锁、轻量级锁和重量级锁。随着锁的竞争,锁可以从偏向锁升级到轻量级锁,再升级的重量级锁,锁可以升级但不能降级。
Java并发编程之synchronized关键字的更多相关文章
- Java 多线程并发编程之 Synchronized 关键字
synchronized 关键字解析 同步锁依赖于对象,每个对象都有一个同步锁. 现有一成员变量 Test,当线程 A 调用 Test 的 synchronized 方法,线程 A 获得 Test 的 ...
- Java并发编程之volatile关键字解析
一内存模型的相关概念 二并发编程中的三个概念 三Java内存模型 四深入剖析volatile关键字 五使用volatile关键字的场景 volatile这个关键字可能很多朋友都听说过,或许也都用过.在 ...
- Java并发编程之volatile关键字
大概是因为项目.业务的原因,工作上几乎还没有使用过多线程相关的功能,相关知识差不多都忘了,所以最近补一下基础. volatile用来修饰共享变量,volatile变量具有 synchronized 的 ...
- 并发编程之synchronized关键字
synchronized关键字 synchronized关键字最主要的三种使用方式的总结 1.修饰实例方法,作用于当前对象实例加锁,进入同步代码块前要获得当前对象实例的锁 2.修饰静态方法,作用于当前 ...
- Java 并发编程之volatile关键字解析
摘录 1. 计算机在执行程序时,每条指令都是在CPU中执行的,而执行指令过程中,势必涉及到数据的读取和写入.由于程序运行过程中的临时数据是存放在主存(物理内存)当中的,这时就存在一个问题,由于CPU执 ...
- Java并发编程之synchronized
在Java编程中,为了保证线程安全,有3种不同的思路1.互斥同步:包括synchronized和lock等. 2.非阻塞同步:如AtomicInteger的increaseAndGet()方法等. 3 ...
- Java并发编程之CAS
CAS(Compare and swap)比较和替换是设计并发算法时用到的一种技术.简单来说,比较和替换是使用一个期望值和一个变量的当前值进行比较,如果当前变量的值与我们期望的值相等,就使用一个新值替 ...
- Java并发编程之CAS二源码追根溯源
Java并发编程之CAS二源码追根溯源 在上一篇文章中,我们知道了什么是CAS以及CAS的执行流程,在本篇文章中,我们将跟着源码一步一步的查看CAS最底层实现原理. 本篇是<凯哥(凯哥Java: ...
- Java并发编程之CAS第一篇-什么是CAS
Java并发编程之CAS第一篇-什么是CAS 通过前面几篇的学习,我们对并发编程两个高频知识点了解了其中的一个—volatitl.从这一篇文章开始,我们将要学习另一个知识点—CAS.本篇是<凯哥 ...
随机推荐
- [leetcode]38. Count and Say数数
The count-and-say sequence is the sequence of integers with the first five terms as following: 1. 1 ...
- Python之路(第二十八篇) 面向对象进阶:类的装饰器、元类
一.类的装饰器 类作为一个对象,也可以被装饰. 例子 def wrap(obj): print("装饰器-----") obj.x = 1 obj.y = 3 obj.z = 5 ...
- mysql c-api 预处理语句
stmt = mysql_stmt_init(mysql) mysql_stmt_prepare(stmt, "SELECT ?", strlen("SELECT ?&q ...
- Json中对日期的处理
前言:Json对日期的处理很特别,我们不能简单的转换而得到我们想要的结果,需要进行特殊处理 一.JSon序列化和反序列化对日期的处理 JsonHelper类: using System.IO; usi ...
- Zookeeper Client基础操作和Java调用
## Zookeeper > Zookeeper目前用来做数据同步,再各个服务之前同步关键信息 i.客户端操作 1. 创建 create [-s] [-e] path data acl -s 为 ...
- 2019.02.27 bzoj4556: [Tjoi2016&Heoi2016]字符串(二分答案+sam+线段树合并)
传送门 题意:给一个字符串SSS. 有mmm次询问,每次给四个参数a,b,c,da,b,c,da,b,c,d,问s[a...b]s[a...b]s[a...b]的所有子串和s[x...y]s[x... ...
- MySQL-5.7安装
2.1 下载mysql 网址:https://www.mysql.com/ [root@localhost ~]# mkdir -p /root/soft/MySQL [root@localhost ...
- VDD,VCC,VSS,VEE,VDDA,VSSA,
VDD是主供电电源,也是IO口输出电平的输入电源.VDDA(A表示模拟)是模拟电源,当使用到模拟信号的时候,比如AD(模数)或者DA(数模)的时候,系统会使用VDDA的电压作为参考电压来.不要求精准使 ...
- Git 的一个教程网站(中文、GUI)
交互教学网站:http://learngitbranching.js.org/ Github Repositry (fork)https://github.com/pcottle/learnGitBr ...
- ubuntu16.04安装最新版docker、docker-compose、docker-machine
安装前说明: 本文将介绍在ubuntu16.04系统下安装和升级docker.docker-compose.docker-machine. docker:有两个版本:docker-ce(社区版)和do ...