整理一下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关键字的更多相关文章

  1. Java 多线程并发编程之 Synchronized 关键字

    synchronized 关键字解析 同步锁依赖于对象,每个对象都有一个同步锁. 现有一成员变量 Test,当线程 A 调用 Test 的 synchronized 方法,线程 A 获得 Test 的 ...

  2. Java并发编程之volatile关键字解析

    一内存模型的相关概念 二并发编程中的三个概念 三Java内存模型 四深入剖析volatile关键字 五使用volatile关键字的场景 volatile这个关键字可能很多朋友都听说过,或许也都用过.在 ...

  3. Java并发编程之volatile关键字

    大概是因为项目.业务的原因,工作上几乎还没有使用过多线程相关的功能,相关知识差不多都忘了,所以最近补一下基础. volatile用来修饰共享变量,volatile变量具有 synchronized 的 ...

  4. 并发编程之synchronized关键字

    synchronized关键字 synchronized关键字最主要的三种使用方式的总结 1.修饰实例方法,作用于当前对象实例加锁,进入同步代码块前要获得当前对象实例的锁 2.修饰静态方法,作用于当前 ...

  5. Java 并发编程之volatile关键字解析

    摘录 1. 计算机在执行程序时,每条指令都是在CPU中执行的,而执行指令过程中,势必涉及到数据的读取和写入.由于程序运行过程中的临时数据是存放在主存(物理内存)当中的,这时就存在一个问题,由于CPU执 ...

  6. Java并发编程之synchronized

    在Java编程中,为了保证线程安全,有3种不同的思路1.互斥同步:包括synchronized和lock等. 2.非阻塞同步:如AtomicInteger的increaseAndGet()方法等. 3 ...

  7. Java并发编程之CAS

    CAS(Compare and swap)比较和替换是设计并发算法时用到的一种技术.简单来说,比较和替换是使用一个期望值和一个变量的当前值进行比较,如果当前变量的值与我们期望的值相等,就使用一个新值替 ...

  8. Java并发编程之CAS二源码追根溯源

    Java并发编程之CAS二源码追根溯源 在上一篇文章中,我们知道了什么是CAS以及CAS的执行流程,在本篇文章中,我们将跟着源码一步一步的查看CAS最底层实现原理. 本篇是<凯哥(凯哥Java: ...

  9. Java并发编程之CAS第一篇-什么是CAS

    Java并发编程之CAS第一篇-什么是CAS 通过前面几篇的学习,我们对并发编程两个高频知识点了解了其中的一个—volatitl.从这一篇文章开始,我们将要学习另一个知识点—CAS.本篇是<凯哥 ...

随机推荐

  1. maven小结

    1.首先要安装maven,我的在: F:\apache-maven-3.0.4 2.手动创建本地仓库的地址为:F:\.m2\repository 3.从windows的环境变量中增加了:M2_HOME ...

  2. linux下sort命令使用详解---linux将文本文件内容加以排序命令

    转载自:http://www.cnblogs.com/hitwtx/archive/2011/12/03/2274592.html linux下sort命令使用详解---linux将文本文件内容加以排 ...

  3. 32.Mysql Cluster

    32.Mysql Cluster Cluster是一组节点的组合.节点分为数据节点.SQL节点.管理节点.节点组合在一起可以为应用提供高可用.高性能.可缩放的Cluster数据管理.数据节点使用NDB ...

  4. javaweb开发3.基于Servlet+JSP+JavaBean开发模式的用户登录注册

    转载孤傲苍狼博客http://www.cnblogs.com/xdp-gacl/p/3902537.html 1.层次比较分明的项目结构图

  5. 21. pt-stalk

    pt-stalk 适用场景:MySQL Server 性能波动出现的频率很低.例如.几天一次MySQL Server 性能波动出现的机率很快.例如.几秒闪过 pt-stalk h=192.168.10 ...

  6. leveldb 学习记录(四) skiplist补与变长数字

    在leveldb 学习记录(一) skiplist 已经将skiplist的插入 查找等操作流程用图示说明 这里在介绍 下skiplist的代码 里面有几个模块 template<typenam ...

  7. javaScrpit 开端

    JavaScript 代码可以直接嵌在网页的任何地方,不过我们通常把JavaScrpit放到<head>中: <html> <head> <script> ...

  8. Vue post提交

    vue中的axios 是不直接支持post方法的,所以我们得绕一下路,我目前在登录的时候运用到了,服务器端用php,可以收到数据 let param = new URLSearchParams(); ...

  9. 小白的CTF学习之路2——二进制数据基础与运算(上)

    今天的第二更,被我拖到了傍晚,嘿嘿,二进制这方面让本就数学不好的我很头疼,所以研究了一段时间 在学习之前我们先了解几个问题: 32位是几个字节? 01011100对于十进制是多少? 00001111向 ...

  10. 学习Acegi应用到实际项目中(4)

    此节介绍:ConcurrentSessionFilter. 在Acegi 1.x版本中,控制并发HttpSession和Remember-Me认证服务不能够同时启用,它们之间存在冲突问题. 在一些应用 ...