Java并发之synchronized关键字

一.基本使用和语义

synchronized可以用于修饰方法或代码块。修饰代码块时锁是后面括号里的对象。修饰方法分为实例方法和静态方法。修饰实例方法时锁是调用方法的对象;修饰静态方法时锁是类对象。再解释一下这个类对象。在java中'一切'都是对象,连对象的模板——类本身也是对象,存储在虚拟机运行时数据区域的方法区。

synchronized是java从语言层面提供的,通过‘互斥同步’来实现并发正确性的机制。它的语义是只有获得锁之后才能执行相应的代码,每次只能有一个线程获取锁。需要注意的是对一个线程来说synchronized同步块是可重入的,对不同线程是互斥的。具体表现如,一个线程获取到synchronized锁进入到一个实例方法中后,其它线程则不能再进入同一个方法或本对象的其它实例方法,因为它们都由同一个锁绑定。同时获取到锁的线程还可以继续调用其它synchronized方法,不会出现自己把自己锁死的情况。

原子性:
基本数据类型的访问读写是具备原子性的;
synchronized反映到字节码的层面是monitorenter和monitorexit。在synchronized块之间的操作也具备原子性。

可见性:
可见性是指一个线程修改了共享变量的值,其他线程能够立即得知这个修改。
volatile、synchronized、final可以实现可见性。
volatile通过变量修改会将新值立即同步回主内存,来保证可见性;
synchronized通过‘对一个变量执行unlocak操作之前,必须先把此变量同步回主内存中’保证可见性。
final:被final修饰的字段在构造器中一旦初始化完成,并且构造器没有把this的引用传递出去,那在其它线程中就能看见final字段的值

有序性:
volatile、synchronized
volatile本身有禁止指令重排序,保证在其之前的语句在其之前执行,其之后的语句在其之后执行。
synchronized:‘一个变量在同一时刻只允许一条线程对其进行lock操作’,这条规则则决定了持有同一个锁的两个同步块只能串行进入。

二.实现原理

Java的线程是映射到操作系统的线程之上的,也就是说线程的调度、阻塞、唤醒等都需要操作系统来帮忙完成,这就涉及到用户态到内核态的切换。

Java中的每个对象都有作为锁的潜质,这是通过Java对象的对象头实现的。Java对象的存储结构由三部分组成对象头、实例数据和填充数据。其中对象头信息又包括Mark Word、类元信息。其中类元信息是指向对象所属类对象的指针。

Mark Word中是一些状态信息,包括锁标志位:重量级锁(synchronized),偏向锁,轻量级锁和GC标记。当处于重量级锁10状态时就是有线程获取了synchronized锁,这时Mark word中还有记录指向monitor对象的指针。对于每一个对象都有一个monitor对象与之对应。monitor对象是实现synchronized的关键。它是使用操作系统互斥量来实现的。维持一个Entry_list记录阻塞的线程队列和一个Wait_list记录调用了wait()方法的队列。

三.锁优化

synchronized是基于互斥同步的,这种实现设计到线程的阻塞,而挂起和恢复线程的操作都需要转入内核态中完成,这些操作给系统的并发性能带来了很大的压力。所以有了以下JVM的优化措施。

3.1自旋锁与自适应锁

获取锁的的时候,如果不成功,不是马上放弃处理时间进入阻塞状态,而是自己循环等待一下。因为阻塞的代价较大,而且大多数时候锁很快就能释放,自旋等待容易等到锁的释放。

自适应的自旋锁,自旋的时间不再固定,如果上一次自旋获得了锁,那么下一次还倾向于认为能自旋成功,所以可以多等一会。反之,如果对于某个锁自旋很少成功,那么之后获取这个锁时倾向于减少等待时间甚至取消自旋。

3.2锁消除

数据只有在被多线程访问时才可能有并发问题,如果JVM判断出在一段代码中,堆上的所有数据都不会逃逸出去而被其他线程访问到,那就可以把它们当做栈上的数据对待,认为它们是线程私有的,同步加锁就不需要了。
eg.jdk1.5之前,String的加法操作会转换为StringBuffer的append()方法,这个方法是用synchronized修饰。而有时候这是不必要的。

3.3锁粗化

消除频繁加锁的影响,如在循环加锁,可以移到循环外部,提交效率。

3.4轻量级锁

实践表明,大多数情况下同步代码并不存在多线程竞争。这种情况下再每次都使用重量级锁的互斥量,开销就很大。这里的轻量是和使用操作系统互斥量来实现的传统锁而言的。MarkWord锁标志位为00时表示处于轻量级锁状态。(锁标志位:00轻量级锁,01未锁定\可偏向,10重量级锁,11GC标志。)

过程:
在代码进入同步块时,如果此同步对象没有被锁定(标志位01),虚拟机首先在当前线程的栈帧中建立一个名为锁记录(Lock Record)的空间,用于存储MarkWord的拷贝。
然后,虚拟机将使用CAS操作尝试将对象的mark word更新为指向Lock Record的指针。如果成功,则该线程就拥有了该对象的锁,且对象处于轻量级锁定的状态。执行完同步块代码后释放锁即可,整个过程不涉及操作系统互斥量等。如果一直没有线程竞争,就会每次都使用轻量级锁。
如果CAS操作失败,虚拟机首先会检查对象的Mark Word是否指向当前线程的栈帧,如果是说明当前线程已经拥有了这个对象的锁,那就可以直接进入同步快继续执行。否则,说明这个锁被其它线程抢占了。那么轻量级锁就要膨胀为重量级锁。
解锁过程也是通过CAS操作来进行的,如果mark word仍然指向这线程的锁记录,那就用CAS操作把当前对象的mark word和栈帧中的displaced mark word换回来,如果替换成功,整个同步过程就完成了。如果失败,说明有其他线程获取过该锁,那就要在释放锁的同时,唤醒被挂起的线程。

3.5偏向锁

偏向锁的意思是这个锁会偏向于第一个获得它的线程,如果在接下来的执行过程中,该锁没有被其他的线程获取,则持有偏向锁的线程将永远不需要再进行同步。

过程:
当锁对象第一次被线程获取的时候,虚拟机会把对象头中的标志位设置为01,即偏向模式。同时使用CAS操作把获取到这个锁的线程的ID记录在对象的Mark Word中,如果CAS操作成功,持有偏向锁的线程以后每次进入这个锁相关的同步块时,虚拟机都可以不再进行任何同步操作。当有另一个线程尝试获取这个锁时,偏向模式就宣告结束。根据锁对象目前是否处于被锁定的状态,撤销偏向后恢复到未锁定或轻量级锁定的状态。

Java并发之基础知识
Java并发之volatile关键字
Java并发之synchronized关键字
Java并发之原子类
Java并发之线程池
Java并发之并发工具类
Java并发之AQS原理
Java并发之ThreadLocal使用和源码分析


如果本文对您有帮助,欢迎关注我的原创微信公众号“Java技术小站”第一时间接收我的更多文章

Java技术小站.png

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

推荐阅读更多精彩内容