多线程知识梳理(2) - synchronized 三部曲之基本使用

一、为什么要使用 synchronized

使用synchronized的原因在于:它能够确保多个线程在同一时刻,只能有一个线程处于方法或者同步块中,它保证了线程对变量访问的可见性和排他性。

二、synchronized 原理

JDK 1.6之前,synchronized的实现是基于对象上的监视器,这也被称为重量锁。默认情况下,每一个对象都有一个关联的Monitor,而每个Monitor包含了一个EntryCount计数器,它是synchronized实现可重入的关键。

JDK 1.6之后,对锁进行了一系列优化的措施,通过引入自旋锁、适应性自旋锁、锁消除、锁粗化、偏向锁、轻量级锁等技术来减少锁操作的开销。

这些优化措施最终的目的是减少锁操作的开销,然而它所改变的只是锁的实现方式,但是加锁和解锁这一基本原则是没有改变的。这篇文章主要是介绍synchronized的使用,因此,在后面的介绍中,我们还是按照比较容易理解的重量锁的方式进行分析,在之后的文章中,我们再来谈一下优化后的实现策略。

2.1 进入同步方法或者代码块

当一个线程执行某个对象的同步方法或者代码块时,会先检查这个对象所关联的Monitor's EntryCount是否为0

  • 如果EntryCount0,那么该线程就会将Monitor’s EntryCount设置为1,并成为该Monitor的所有者,接着执行该方法或者代码块中的语句。
  • 如果EntryCount不为0,这时会去检查对象所关联的Monitor的持有者是哪一个线程:
  • 第一种情况:持有该Monitor的线程就是当前正在尝试获取Monitor的线程,那么将EntryCount的数值加1,继续执行方法或者代码块中的语句。
  • 第二种情况:持有该Monitor的是其它的线程,那么该线程进入阻塞状态,直到EntryCount的数值变为0

2.2 退出同步方法或者代码块

当一个线程从同步方法或者代码块退出时,会将EntryCount1,如果EntryCount变为0,那么该线程会释放它所持有的Monitor。之前那些阻塞在synchronized的线程会尝试去获取Monitor,成功获取Monitor的线程可以进入同步方法或者代码块。

三、synchronized 使用

对于synchronized的使用,我们有两种分类方法:

  • 根据使用场景分类
  • 根据Monitor关联的对象分类。

3.1 根据使用场景分类

很多介绍synchronized的文章,都是通过使用场景进行分类的,一般来说可以分为如下四种使用场景,而每种场景下根据Monitor所关联的对象不同,又会衍生出另外的用法:

  • 静态方法
    //静态方法,使用的是Class类锁
    synchronized public static void staticMethod() {}
  • 静态方法代码块
    private static final byte[] mStaticLockByte = new byte[1];

    //静态方法代码块1,使用的是Class类锁
    public static void staticBlock1() {
        synchronized (SynchronizedObject.class) {}
    }

    //静态方法代码块2,使用的是内部静态变量锁
    public static void staticBlock2() {
        synchronized (mStaticLockByte) {} 
    }
  • 普通方法
    //普通方法,使用的是调用该方法的对象锁
    synchronized public void method() {}
  • 普通方法代码块
    private static final byte[] mStaticLockByte = new byte[1];
    private final byte[] mLockByte = new byte[1];

    //普通方法代码块1,使用的是Class类锁
    public void block1() {
        synchronized (SynchronizedObject.class) {}
    }

    //普通方法代码块2,使用的是mLockByte的变量锁
    public void block2() {
        synchronized (mLockByte) {} //变量需要声明为final
    }
    
    //普通方法代码块3,使用的是mStaticLockByte的变量锁
    public void block3() {
        synchronized (mStaticLockByte) {} 
    }

    //普通方法代码块4,使用的是调用该方法的对象锁
    public void block4() {
        synchronized (this) {}
    }

3.2 根据 Monitor 关联的对象分类

根据使用场景进行分类,主要是为了让大家知道如何使用synchronized关键字,然而要真正地理解synchronized,就需要结合第二节谈到的synchronized原理,其实3.1中谈到的多种场景,都是和Monitor有关,那么从和Monitor关联的对象来看,我们重新对3.1中的8种场景重新进行分类:

  • Class对象:
  • 静态方法
  • 静态方法代码块1 - SynchronizedObject.class
  • 普通方法代码块1 - SynchronizedObject.class
  • 调用方法的对象
  • 普通方法
  • 普通方法代码块4 - this
  • 静态对象
  • 静态方法代码块2 - mStaticLockByte
  • 普通方法代码块3 - mStaticLockByte
  • 非静态对象
  • 普通方法代码块1 - mLockByte

如果使用场景属于上面的同一个分类当中,那么才有可能产生线程阻塞在synchronized关键字的情况,举一个例子,如果A线程通过静态方法访问(分类一)并且没有从该方法退出:

  • 这时B线程是通过一个对象的普通方法来访问(分类二),那么是不会阻塞的,这是因为调用该方法的对象所关联的Monitor没有被持有。
  • 如果B线程使用的是静态方法代码块来访问,而该静态方法代码块使用的是SynchronizedObject.class来修饰(分类一),由于这两种使用场景是属于同一个分类,那么就会B线程就会进入阻塞状态,这是因为SynchronizedObject类所关联的Monitor已经被A线程持有了。

四、小结

从表面上来看,synchronized的使用可以简单地分为同步方法和同步代码块,但是究竟在什么情况下会导致一个线程在synchronized上阻塞,则需要分析synchronized方法所尝试获取的Monitor的是否已经被其它线程持有了。

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

推荐阅读更多精彩内容