Java中的锁系列1

整篇文章,我想由浅到深开始写。刚开始可能会有一些比较基础的内容。

一、通过一个典型的并发问题,了解锁到底有什么用

开10个线程,对count变量进行++操作,每个线程执行50次++操作。


10个线程,每个线程加50次,理论上,应该是500;

但是,让我们看下实际的运行结果。

第一次运行结果:


第二次运行结果:


不是500也就算了,每次运行的结果还不一样。很显然,并发了。然后,我们加上synchronized关键字试试。


结果如下:


执行结果正确了。但是,我们也发现增加synchronized后,比增加之前执行时间长了很多。

二、锁消除和锁粗化

不难发现 , 是因为我们对Thread.currentThread().sleep(100);也加了锁,导致运行变慢。

然后我们将synchronized的位置改一下。


运行结果如下:


运行结果正确,但是运行时间快了很多。所以,写代码的时候,一定要注意,不该锁的代码,不要锁。我们通常也把这种原则叫做锁消除。

但是!

如果要是我们频繁的lock和unlock,同样会导致大量的开销。这个时候,我们需要将多个连续的锁扩展成一个范围更大的锁。这个叫做锁粗化。

有的同学可能会说了,我粗也不好,细也不好,你想让我一粗一细一粗一细么!

好吧,这个就看自己怎么去衡量了…

三、ReentrantLock类

Java里除了synchronized关键字外,还有很多其他的方式也可以避免并发问题。

比如典型的ReentrantLock,又叫做可重入锁。

ReentrantLock是继承自Lock接口。


除了ReentrantLock外,还有ReentrantReadWriteLock


我们可以发现,ReentrantReadWriteLock并没有直接实现Lock接口。

但是,ReentrantReadWriteLock有两个方法,可以获取ReadLock和WriteLock,而ReadLock和WriteLock实现了Lock接口。ReentrantReadWriteLock的具体使用和实现我们将在后面的文章中研究。

本文里,我们先了解下ReentrantLock。

首先, 我们来创建一个可重入锁ReentrantLock,先lock,然后在finally里unlock。


我们来看下执行效果:


什么鬼?明明锁起来了,怎么结果不是500!

检查下代码, 发现ReentrantLock reentrantLock = new ReentrantLock();这行代码居然写在run()方法里面。每次执行都会创建一把新的锁,当然没用......。那应该怎么做呢?

肯定是当成成员变量。


改好之后,再看下效果:


所以,一定记得要保证:需要同步的代码块拿到的是同一把锁。用吐槽大会池子的话说:知识点啊有木有。

四、什么是可重入锁?怎么证明synchronized和ReentrantLock都是可重入的?

前面一直在说ReentrantLock,字面翻译过来,也就是可重入锁,但是一直不明白可重入锁到底是个什么鬼?

其实,可重入锁是一个概念,并不就仅仅指ReentrantLock,虽然它翻译过来就是这个意思。

可重入锁,也叫做递归锁,指的是同一线程外层函数获得锁之后 ,内层递归函数仍然有获取该锁的代码,但不受影响。

通俗点说就是在同一个线程里调lock()之后,哪怕不释放,然后再调一次lock()方法,又可以拿到锁。可重入锁主要是为了解决递归调用产生的死锁问题。其实synchronized也是可重入锁的一种,因为写了synchronized关键字之后,递归调用可以正常执行。

为了加深理解,我们自己写一个不可重入锁,来对比一下可重入锁。

我们自己写的锁名字叫MyLock,一样也继承Lock接口。


然后我们用MyLock来锁一下试试:


执行结果如下:


结果正确!说明我们实现了锁的基本功能。

然后我们来实验一下需要可重入的场景试试。

我们在run方法里,执行两次count++操作,对每个count++执行一次加锁操作,但是不解锁。

代码如下:


执行结果如下:


可以看出,用我们自己写的MyLock锁,执行了一次,程序就死锁了。

然后我们把lock换成ReentrantLock再来一次。

private static Lock lock new ReentrantLock();

再次执行,结果如下:


跟预期结果一样。

然后我们再改成Synchronized试试。


结果同上。

通过这个实验,我们可以证明,ReentrantLock和synchronized确实是可重入锁。

五、synchronized和ReentrantLock的比较

那么问题来了,既然synchronized和ReentrantLock都是可重入锁,synchronized那么方便,还需要ReentrantLock干啥?难道蛋疼?

我们可以看下ReentrantLock实现lock的方式。


然后Sync是继承自传说中的AbstractQueuedSynchronizer(AQS)。


另外在ReentrantLock内部还定义了另外两个类,分别是FairSync和NonFairSync,这两个类就是分别对应的锁公平分配和不公平分配的两个实现,它们都继承自Sync(类图已经清晰的描述出来了继承结构)。有关锁的分配和释放逻辑都是封装在了AQS里面。

而Synchronized实现的同步和上面提到的AQS的方式是不同的,AQS实现了一套自己的算法来实现共享资源的合理控制(具体算法实现,下文分析),而Synchronized实现的同步控制是基于java内部的对象锁的。

那什么是java内部的对象锁呢?

Java内部对象锁:JVM中每个对象和类实际上都与一把锁与之相关联,对于对象来说,监视的是这个对象变量,对于类来说,监视的是类变量。当虚拟机装载类时,会创建一个Class类的实例,锁住的实际上是这个类对应的Class累的实例。对象锁是可重入的,也就是说一个对象或者类上的锁是可以累加的。

然后网上也有一些ReentrantLock和synchronized的性能比较。

http://blog.csdn.net/lantian0802/article/details/8948696

各种数据都显示,ReentrantLock无论哪方面都比synchronized好。而且支持更多的特性,比如时间锁等候、可中断锁等候、无块结构锁、多个条件变量或者锁投票。

但是!是的,我们来但是了!

很多大神还是建议能用synchronized开发的时候,尽量别用ReentrantLock,除非能证明synchronized已经不适合所在场景。因为,大多数synchronized块几乎从来没有出现过争用,而ReentrantLock比synchronized优秀是体现在出现高争用的场景。但是一旦忘记写unlock了,那就是死锁!


下一篇,我们将具体讲解java内部的对象锁,包括偏向锁、轻量级锁、重量级锁和自旋锁。

Java中的锁系列2

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

推荐阅读更多精彩内容