一、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

    开启正文之前,先说一下源码剖析这一系列,就以"死磕到底"的精神贯彻始终,最少追踪到JVM指令(再往下C语言实现了). =========正文分割线===========  Sync ...

  2. 一点一点看JDK源码(三)java.util.ArrayList 前偏

    一点一点看JDK源码(三)java.util.ArrayList liuyuhang原创,未经允许禁止转载 本文举例使用的是JDK8的API 目录:一点一点看JDK源码(〇) 1.综述 ArrayLi ...

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

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

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

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

  5. Django Rest Framework源码剖析(三)-----频率控制

    一.简介 承接上篇文章Django Rest Framework源码剖析(二)-----权限,当服务的接口被频繁调用,导致资源紧张怎么办呢?当然或许有很多解决办法,比如:负载均衡.提高服务器配置.通过 ...

  6. (文字版)Qt信号槽源码剖析(三)

    大家好,我是IT文艺男,来自一线大厂的一线程序员 上节视频给大家讲解了Qt信号槽的Qt宏展开推导:今天接着深入分析,进入Qt信号槽源码剖析系列的第三节视频. Qt信号槽宏推导归纳 #define si ...

  7. Dubbo源码剖析三之服务注册过程分析

    Dubbo源码剖析二之注册中心 - 池塘里洗澡的鸭子 - 博客园 (cnblogs.com)中对注册中心进行了简单的介绍,对Dubbo整合Zookeeper链接源码进行了详细分析.本文接着对服务注册过 ...

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

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

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

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

随机推荐

  1. 2010年腾讯前端面试题学习(js部分)

    看了牛人写的回忆文章,里面有2010年腾讯的前端面试题,里面涉及到不少基础性的问题,学习一下:) 原文地址:https://segmentfault.com/a/1190000012998107 js ...

  2. kbmMW SmartService控制返回类型

  3. kbmMW基于硬件生成随机数

    按作者的说法,Delphi提供的生成随机数不是真正随机的,因为他是根据种子计算的,即种子+算法生成的随机数,如果被人知道原始种子值和算法的调用次数,则可以重现随机数,因此在安全领域,这是不安全的.同时 ...

  4. 分类算法的R语言实现案例

    最近在读<R语言与网站分析>,书中对分类.聚类算法的讲解通俗易懂,和数据挖掘理论一起看的话,有很好的参照效果. 然而,这么好的讲解,作者居然没提供对应的数据集.手痒之余,我自己动手整理了一 ...

  5. wx小程序 使用字体

    1.下载项目下的字体库 2.解压复制iconfont.css中的代码到,小程序 app.wxss 3.使用: //icon-begindate表示开始时间的图标 <text class=&quo ...

  6. 一个跳转提示页面---JS

    //一个跳转提示页面   <script type="text/javascript">   var s=5;     function go(){        do ...

  7. jQuery .each()方法与.data()方法

    .each(callback): 每次执行传递进来的函数时,函数中的this关键字都指向一个不同的DOM元素(每次都是一个不同的匹配元素).而且,在每次执行函数时,都会给函数传递一个表示作为执行环境的 ...

  8. c++函数参数类型-引用、指针、值

    c++函数参数类型-引用.指针.值 https://www.cnblogs.com/lidabo/archive/2012/05/30/2525837.html

  9. c# 休眠后 定时唤醒

    源码见附件,执行唤醒功能前需要先对电源进行设置如下图: 源码

  10. [Data Structure] Stack Implementation in Python

    We can realize a Stack as an adaptation of a Python List. S.push(e)=L.append(e) S.pop()=L.pop() S.to ...