Java并发——Synchronized及其实现原理

Synchronized是Java中实现进程同步最简单的一种方式,Synchronized主要有以下三个作用:

  • 保证互斥性
  • 保证可见性
  • 保证顺序性

接下来我们就来看下Synchronized的实现原理,看看Synchronized是如何实现上述三个作用的。

Synchronized有三种常用方法:

  • 修饰普通方法
  • 修饰静态方法
  • 修饰代码块

具体的用法这里就不展开了,不熟悉的朋友建议先试用一下。

1 Synchronized实现原理

先来看下下面这段代码:

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

这是一个典型的Synchronized修饰代码块的例子,Synchronized的对象是实例对象。意味着对一个SynchronizedDemo对象,同一时间内只能有一个线程可以执行method方法。

接下来我们来看看上述代码对应的字节码:

这里写图片描述

可以看到synchronized所覆盖的代码块的首尾部分分别加上了monitorentermonitorexit。JVM中对于上述两条指令的解释如下:

  • monitorenter:

    Each object is associated with a monitor. A monitor is locked if and only if it has an owner. The thread that executes monitorenter attempts to gain ownership of the monitor associated with objectref, as follows:
    • If the entry count of the monitor associated with objectref is zero, the thread enters the monitor and sets its entry count to one. The thread is then the owner of the monitor.
    • If the thread already owns the monitor associated with objectref, it reenters the monitor, incrementing its entry count.
    • If another thread already owns the monitor associated with objectref, the thread blocks until the monitor's entry count is zero, then tries again to gain ownership.

    大意就是:

    每一个对象有一个相关联的监视器(monitor),当monitor被占用时便被锁定住。当执行monitorenter执行时,当前线程尝试获取monitor

    • 如果当前monitor的进入数为0,则说明monitor未被占用,则当前线程占有该monitor,同时monitor的进入数变为1
    • 如果当前monitor进入数不为0,且monitor的占用者是当前线程,则可以重复占用该monitor,同时进入数加1
    • 如果其他线程占有了该monitor,则线程进入阻塞状态,直到monitor的进入数重新变为0,再重新尝试获取所有权

  • monitorexit:

    The thread that executes monitorexit must be the owner of the monitor associated with the instance referenced by objectref.
    The thread decrements the entry count of the monitor associated with objectref. If as a result the value of the entry count is zero, the thread exits the monitor and is no longer its owner. Other threads that are blocking to enter the monitor are allowed to attempt to do so.

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

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

通过上述两段描述便不难理解Synchronized的实现原理了。Synchronized实际是通过关联一个对象的monitor来实现的。在前文的代码demo中,关联的对象实际就是SynchonizedDemo实例对象的monitor。其实wait/notify等方法也依赖于monitor对象,这就是为什么只有在同步的块或者方法中才能调用wait/notify等方法,否则会抛出java.lang.IllegalMonitorStateException的异常的原因。

接下来再来看看Synchronized修饰方法的场景:

public class SynchronizedMethod {
     public synchronized void method() {
         System.out.println("Hello World!");
     }
 }

对应的字节码为:

这里写图片描述

从反编译的结果来看,方法的同步并没有通过指令monitorenter和monitorexit来完成(理论上其实也可以通过这两条指令来实现),不过相对于普通方法,其常量池中多了ACC_SYNCHRONIZED标示符。JVM就是根据该标示符来实现方法的同步的:当方法调用时,调用指令将会检查方法的 ACC_SYNCHRONIZED 访问标志是否被设置,如果设置了,执行线程将先获取monitor,获取成功之后才能执行方法体,方法执行完后再释放monitor。在方法执行期间,其他任何线程都无法再获得同一个monitor对象。 其实本质上没有区别,只是方法的同步是一种隐式的方式来实现,无需通过字节码来完成。

当Synchronized修饰不同方法时,获取的monitor对象不同:

  • 修饰对象方法:此时获取的monitor为实例对象(即this)的monitor
  • 修饰类方法:此时获取的monitor为类class对象(如Synchronized.class)的monitor

通过上述解释,相信大家已经知道Synchronized是如何保证互斥性的,那么其是怎么实现可见性和顺序性的呢?其实也跟monitor相关:

  • 可见性:执行到monitorenter时,线程会重新从主内存中将数据同步到本地工作内存,从而保证其可以看到其他线程的修改。同时执行monitorexit时,线程也会将本地工作内存的数据同步到主内存中
  • 有序性:monitorenter、monitorexit修饰的代码将禁止进行重排序
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容

  • 一、Synchronized的基本使用Synchronized是Java中解决并发问题的一种最常用的方法,也是最简...
    yeying12321阅读 659评论 0 0
  • Java8张图 11、字符串不变性 12、equals()方法、hashCode()方法的区别 13、...
    Miley_MOJIE阅读 3,693评论 0 11
  • 最近公司要开发一个移动端的养成类网页游戏(就是用手点各种按钮最后你会找到一个女朋友=。=),要求横屏显示,不能竖屏...
    stois阅读 85,947评论 35 72
  • 人是群居动物,一个人孤零零的生活在这个世界上,哪怕有再多钱,也不会快乐。所以我们依赖每一个出现在生命中的人,而这也...
    后果呢过阅读 637评论 0 0
  • 我一直坚信很多人在生活中时刻保持着热情 阳光四射 无时无刻不快乐 努力想分享给身边朋友一些正能量 而这些无非是想骗...
    wuli北枳阅读 459评论 0 0