一、Synchronized作用

(1)确保线程互斥的访问同步代码

(2)保证共享变量的修改能够及时可见

(3)有效解决重排序问题。(Synchronized同步中的代码JVM不会轻易优化重排序)

二、Synchronized常见用法分析

1.修饰普通方法

 package lock;

 /**
*
* @ClassName:SynchronizedDemo
* @Description:测试synchronized
* @author diandian.zhang
* @date 2017年4月1日下午7:02:34
*/
public class SynchronizedDemo { public synchronized void method1(){
System.out.println("进入方法1");
try {
System.out.println("方法1执行");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("方法1 end");
} public synchronized void method2(){
System.out.println("进入方法2");
try {
System.out.println("方法2执行");
Thread.sleep(000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("方法2 end");
} public static void main(String[] args) {
SynchronizedDemo demo = new SynchronizedDemo();
new Thread(new Runnable() {
@Override
public void run() {
demo.method1();
}
}).start(); new Thread(new Runnable() {
@Override
public void run() {
demo.method2();
}
}).start();
}
}

结果:

 进入方法1
方法1执行
方法1 end
进入方法2
方法2执行
方法2 end

可见:修饰普通方法,线程2需要等待线程1的method1执行完成才能开始执行method2方法,方法级别串行执行。

2.修饰静态方法

 package lock;

 /**
*
* @ClassName:SynchronizedDemo2
* @Description:修饰静态方法
* @author diandian.zhang
* @date 2017年4月5日上午10:48:56
*/
public class SynchronizedDemo2 { public static synchronized void method1(){
System.out.println("进入方法1");
try {
System.out.println("方法1执行");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("方法1 end");
} public static synchronized void method2(){
System.out.println("进入方法2");
try {
System.out.println("方法2执行");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("方法2 end");
} public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
SynchronizedDemo2.method1();
}
}).start(); new Thread(new Runnable() {
@Override
public void run() {
SynchronizedDemo2.method2();
}
}).start();
}
}

运行结果:

 进入方法1
方法1执行
进入方法2
方法1 end
方法2执行
方法2 end

可见:修饰静态方法,本质是对类的同步,任何实例调用方法,都类级别串行(每个实例不一定串行)执行。

3.修饰代码块

 package lock;

 /**
*
* @ClassName:SynchronizedDemo3
* @Description:Synchronized修饰代码块
* @author diandian.zhang
* @date 2017年4月5日上午10:49:50
*/
public class SynchronizedDemo3 { public void method1(){
System.out.println("进入方法1");
try {
synchronized (this) {
System.out.println("方法1执行");
Thread.sleep(3000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("方法1 end");
} public void method2(){
System.out.println("进入方法2");
try {
synchronized (this) {
System.out.println("方法2执行");
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("方法2 end");
} public static void main(String[] args) {
SynchronizedDemo3 demo = new SynchronizedDemo3();
new Thread(new Runnable() {
@Override
public void run() {
demo.method1();
}
}).start(); new Thread(new Runnable() {
@Override
public void run() {
demo.method2();
}
}).start();
}
}

运行结果:

 进入方法1
方法1执行
进入方法2
方法1 end
方法2执行
方法2 end

可见,修饰代码块,只锁住代码块的执行顺序。代码块级别串行。(例如上面的方法1和方法2没能串行,因为锁住的是同一个对象,但是同步代码块只包住了方法中的一部分)

三、Synchronized 原理

实际上,JVM只区分两种不同用法 1.修饰代码块 2.修饰方法。什么,你不信?好吧,上SE8规范:http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-3.html#jvms-3.14

上图中,红框框中说明了,1.monitorenter+monitorexit(上图中的onlyMe方法中同步代码块) 2.修饰方法

这一切都是规范说的,下面自测一下吧~

下面,我们通过JDK自带工具反编译,查看包含java字节码的指令。

3.1 synchronized修饰代码块

java源码如下:

 public class SynchronizedDemo {
public void method (){
synchronized (this) {
System.out.println("method 1 start!!!!");
}
}
}

javac -encoding utf-8 SynchronizedDemo.java 编译生成class 后,javap -c 反编译一下,看指令:

这里着重分析2个monitorenter、monitorexit这两个指令。这里以JSE8位为准,查到属于JVM指令集。官网各种API、JVM规范,指令等,传送门:http://docs.oracle.com/javase/8/docs/。

1.monitorenter监视器准入指令

主要看上图中Description:

每个对象有一个监视器锁(monitor)。当monitor被占用时就会处于锁定状态,线程执行monitorenter指令时尝试获取monitor的所有权,过程如下:

1.如果monitor的进入数为0,则该线程进入monitor,然后将进入数设置为1,该线程即为monitor的所有者。

2.如果线程已经占有该monitor,只是重新进入,则进入monitor的进入数加1.

3.’如果其他线程已经占用了monitor,则该线程进入阻塞状态,直到monitor的进入数为0,再重新尝试获取monitor的所有权。

2.monitorexit监视器释放指令

主要看上图中Description:

1.执行monitorexit的线程必须是objectref所对应的monitor的所有者。

2.指令执行时,monitor的进入数减1,如果减1后进入数为0,那线程退出monitor,不再是这个monitor的所有者。其他被这个monitor阻塞的线程可以尝试去获取这个 monitor 的所有权。

3.2 synchronized修饰方法

java源码如下:

 package lock;

 /**
*
* @ClassName:SynchronizedDemo0
* @Description: Synchronized修饰方法
* @author diandian.zhang
* @date 2017年4月5日下午6:18:12
*/
public class SynchronizedDemo0 {
public synchronized void method (){
System.out.println("method start!!!!");
}
}

javap -v 查看class文件,发现method上加了同步标签,本质上还是monitor

3.3 synchronized终极原理C++实现
 
 
四、总结
  
JDK一直没有放弃synchronized且一直在优化,到目前JDK8依然广泛使用。本文从功能、常见用法、源码实现三方面彻底剖析了synchronized锁。相信读者会有所收获。

========附言分割线=====

附:全文参考http://www.cnblogs.com/paddix/p/5367116.html

jdk源码剖析:Synchronized的更多相关文章

  1. jdk源码剖析三:锁Synchronized

    一.Synchronized作用 (1)确保线程互斥的访问同步代码 (2)保证共享变量的修改能够及时可见 (3)有效解决重排序问题.(Synchronized同步中的代码JVM不会轻易优化重排序) 二 ...

  2. jdk源码剖析二: 对象内存布局、synchronized终极原理

    很多人一提到锁,自然第一个想到了synchronized,但一直不懂源码实现,现特地追踪到C++层来剥开synchronized的面纱. 网上的很多描述大都不全,让人看了不够爽,看完本章,你将彻底了解 ...

  3. jdk源码剖析一:OpenJDK-Hotspot源码包目录结构

    开启正文之前,先说一下源码剖析这一系列,就以“死磕到底”的精神贯彻始终,JDK-->JRE-->JVM(以openJDK代替) 最近想看看JDK8源码,但JDK中JVM(安装在本地C:\P ...

  4. jdk源码剖析四:JDK1.7升级1.8 HashMap原理的变化

    一.hashMap数据结构 如上图所示,JDK7之前hashmap又叫散列链表:基于一个数组以及多个链表的实现,hash值冲突的时候,就将对应节点以链表的形式存储. JDK8中,当同一个hash值(T ...

  5. 1.1 jvm核心类加载器--jdk源码剖析

    目录 前提: 运行环境 1. 类加载的过程 1.1 类加载器初始化的过程 1.2 类加载的过程 1.3 类的懒加载 2. jvm核心类加载器 3. 双亲委派机制 4. 自定义类加载器 5. tomca ...

  6. jdk源码剖析五:JDK8-废弃永久代(PermGen)迎来元空间(Metaspace)

    目录 1.背景 2.为什么废弃永久代(PermGen) 3.深入理解元空间(Metaspace) 4.总结 ========正文分割线===== 一.背景 1.1 永久代(PermGen)在哪里? 根 ...

  7. 【并发编程】【JDK源码】CAS与synchronized

    线程安全 众所周知,Java是多线程的.但是,Java对多线程的支持其实是一把双刃剑.一旦涉及到多个线程操作共享资源的情况时,处理不好就可能产生线程安全问题.线程安全性可能是非常复杂的,在没有充足的同 ...

  8. Thread类源码剖析

    目录 1.引子 2.JVM线程状态 3.Thread常用方法 4.拓展点 一.引子 说来也有些汗颜,搞了几年java,忽然发现竟然没拜读过java.lang.Thread类源码,这次特地拿出来晒一晒. ...

  9. 转:【Java集合源码剖析】Hashtable源码剖析

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/36191279 Hashtable简介 Hashtable同样是基于哈希表实现的,同样每个元 ...

随机推荐

  1. win8配置JDK

    有很多新手朋友对win7 和win8里的环境变量不是很熟悉,下面我整理了一下: 首先要说一下,win7里和win8配置方法是相同的,配置之前先去百度一下 JDK 然后找到自己电脑系统对应的jdk版本下 ...

  2. 基于CPS变换的尾递归转换算法

    前言 众所周知,递归函数容易爆栈,究其原因,便是函数调用前需要先将参数.运行状态压栈,而递归则会导致函数的多次无返回调用,参数.状态积压在栈上,最终耗尽栈空间. 一个解决的办法是从算法上解决,把递归算 ...

  3. 20155304田宜楠2006-2007-2 《Java程序设计》第一周学习总结

    20155304田宜楠2006-2007-2 <Java程序设计>第一周学习总结 教材学习内容总结 - 浏览教材,根据自己的理解每章提出一个问题 第一章 除了书上提到的开发工具还有什么适合 ...

  4. VS2015在Windows 10 下面安装经验

    实体机环境:Windows 10 专业版(2017年2月28日 官方下载版本) VS2015:cn_visual_studio_enterprise_2015_with_update_3_x86_x6 ...

  5. BOM元素之window对象

    在浏览器中,window对象有双重角色,它既是通过JavaScript访问浏览器窗口的一个接口,又是ECMAScript规定的Global对象.这意味着在网页中定义的任何一个对象.变量和函数,都以wi ...

  6. 每天一个Linux命令(02)--cd命令

    Linux cd 命令可以说是Linux中最基本的命令语句,其他的命令语句都要进行操作,都是建立在使用 cd命令基础上的. 所以,学习Linux常用命令,首先就要学好 cd 命令的使用技巧. 1.命令 ...

  7. Java版本

    Java版本 Java版本分为J2SE(Java 2 Standard Edition,Java标准版).J2ME(Java 2 Micro Edition,Java微型版本)和J2EE(Java 2 ...

  8. Java面试10|数据库相关

    1.ID分配单点问题 系统使用一张表的自增来得到订单号,所有的订单生成必须先在这里insert一条数据,得到订单号.分库后,库的数量变多,相应的故障次数变多,但由于单点的存在,故障影响范围并未相应的减 ...

  9. Java豆瓣电影爬虫——模拟登录的前世今生与验证码的爱恨情仇

    前言 并不是所有的网站都能够敞开心扉让你看个透彻,它们总要给你出些难题让你觉得有些东西是来之不易的,往往,这也更加激发你的激情和斗志! 从<为了媳妇的一张号,我与百度医生杠上了>里就有网友 ...

  10. 软件测试之fault、error和failure的理解

    (1)  Identify the fault : The first element of the array is not looped. "for(int i=x.length-1;i ...