Java 并发学习之synchronized关键字

一、前言

该篇文章是基于我的日常使用经验及看书学习的总结,文章中难免会出现疏漏或者理解不正确的地方,如果读者发现问题,可通过邮箱(hongweijin1993#gmail.com)与我联系,谢谢。

二、synchronized三个特性

1.原子性

此处的原子性说的是保证了代码块或者方法为最小执行单位,要么全部成功,要么全部失败,不存在中间状态。

2.内存可见性

谈到可见性的时候,我们应该首先清楚,在jvm中分为主存工作内存,工作内存是当前线程私有的区域,而主存是所有线程共享的区域。

使用synchronized关键字的时候会创建一个内存屏障,内存屏障指令保证了所有CPU操作结果都直接刷新到主存中。

对于共享变量来说,每个线程的工作内存中都会存有一个副本,当a线程修改了共享变量的值之后,会先缓存到当前线程的工作内存中。当加锁之后,缓存会失效,从而保证每次修改都会刷新到主存中。同时读取共享变量也是直接从主存中读取,这样就能保证thread1修改了变量的值之后,thread2能够在读取的时候读到最新的值。

可见性中的的可见其实是对进入到同步块中的线程可见。

synchronized关键字对于非同步块中的变量也有可能做到内存可见,不过目前没有权威的说法来支持,不过有个demo可以看一看

3.有序性

有序性是指程序按照代码的先后顺序执行,synchronized关键字无法禁止指令重排序和处理器优化(这块内容可以看看volatile的语意)。

如果在本线程内观察,所有操作都是天然有序的。如果在一个线程中观察另一个线程,所有操作都是无序的。

三、synchronized的使用

1.用法方法上
1.1 普通的实例方法
public class SynchronizedMethod{
    //对实例对象加锁,每次new对象都会生成新的实例对象
    public synchronized void println(){
        System.out.println("synchronized instance method");
    }    
}
1.2 静态方法
public class SynchronizedStaticMethod{
    //是对Class对象加锁
    public synchronized static void println2(){
        System.out.println("synchronized static method");
    }
    //SynchronizedTest.class 是Class对象,只有一个
}
1.3 有继承关系的方法(其实也就是普通的实例方法,此处仅用来说明内置锁的重入)
class Widget{
    //method2
    public synchronized void doSomething{
        System.err.println("----widget----");
    }
}
public class class LoggingWidget extends Widget{
    //method1
    public synchronized void doSomething{
        System.err.println("----logging widget----");
        super.doSomething();
    }
    
    public static void main(String[] args){
        Widget widget = new LoggingWidget();
        widget.doSomething();
    }
}

上面的代码块选自Java并发编程实战,此时执行main函数时,锁住的是LoggingWidget对象。

1.当主线程执行到method1时,获取到了LoggingWidget对象上的锁。

2.当主线程执行到method2时,再次遇到synchronized关键字,此时重入

3.当执行完method2时,退出一次

4.当执行完method1时,再退出一次

可能会产生疑问就在与上面的第二条,锁重入了。我们知道synchronized加在实例方法上的时候,锁住的是实例对象,此时线程持有了该实例对象上的锁,当再次遇到synchronized的时候,锁还是原有实例的,这个时候锁重入了。

2.用在代码块上
2.1 锁住Class对象
public class SynchronizedClass{
    public void println(){
        synchronized(SynchronizedClass.class){
            System.out.println("synchronized Class object");
        }
    }
}
2.2 锁住实例对象
public class SynchronizedInstance{
    public void println(){
        //对实例对象加锁,this换成其他对象也是同理
        synchronized(this){
            System.out.println("synchronized instance objcet");
        }
    }
}
3.总结

1.Java中每个对象都会有一个monitorsynchronized实际上是通过monitor锁住对象的

2.Class对象和实例对象的区别(实例对象是每次new出来的对象,Class对象是ClassName.class对象)

3.同一个类中两个synchronized static方法之间构成同步,因为锁住的都是Class对象

4.同一个类中synchronized static方法和synchronized方法不构成同步,因为一个锁住Class对象,一个锁住实例对象

5.谁调用加锁的实例方法,就获取谁身上的锁

6.内置锁是可以重入的。

四、synchronized的实现原理

1.当synchronized用在代码块上的时候,我们使用javap指令反编译(javap -c SynchronizedBlock)上面代码的时候会发现两个汇编指令:monitorentermonitorexit
public class SynchronizedBlock{
    public void test(){
        synchronized(this){}
    }
}
image-20180921140348995

从上图我们可以看到反编译后的指令,这里面出现了一条monitorenter指令和两条monitorexit指令,monitorenter很好理解,通过这条指令获取到锁,然后进入代码块。那么两条monitorexit指令作何解释?

这是因为加锁时可能出现两种退出同步块的方式,一种是正常执行完退出,另一种就是同步块中出现异常,此时也会退出同步块。这两条指令第一条是用来正常退出的,第二条是编译器自己加上来用于异常退出同步块的。

2.当synchronized用在方法上的时候,反编译会看到方法上被加上ACC_SYNCHRONIZED指令,我们对如下代码使用javap -v SynchronizedMethod指令反编译
public class SynchronizedMethod{
    public synchronized void test(){}
}
image-20180921135746665

从上图的红框中我们可以看到该关键字,在不同的jvm中会做不同的实现,此处参考R大的读书笔记

五、参考资料

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

推荐阅读更多精彩内容