android 多线程 — reentrantLock 重入锁

reentrantLock 、 condition 是 JAVA 1.6 时推出的,也是用来实现多线程同步的,和 synchronized 干的事一样,用法页差不多,但是比 synchronized 要灵活

其中 reentrantLock 叫重入锁,condition 是阻塞条件,我们直接啊看用法来了解这2个类

实现锁的功能

public class MyService {

    private Lock lock = new ReentrantLock();

    public void testMethod() {
        lock.lock();
        for (int i = 0; i < 5; i++) {
            System.out.println("ThreadName=" + Thread.currentThread().getName()
                    + (" " + (i + 1)));
        }
        lock.unlock();
    }
}

synchronized 因为本身是关键字,只能实现标记,本身不含锁,需要我们指定对象锁。而新的 API ReentrantLock 本身就是把锁,不用再依托别人了。

ReentrantLock 在使用上类似于 synchronized 的同步代码块,我们直接在需要的位置, new 一个 ReentrantLock 锁出来,然后 lock() 就能锁定同步,unlock() 就能解锁同步,注意unlock() 方法推荐写在 finnaly 里面

Condition 来阻塞线程并释放锁

public class MyService {

    private Lock lock = new ReentrantLock();
    private Condition condition=lock.newCondition();
    public void testMethod() {
        
        try {
            lock.lock();
            System.out.println("开始wait");
            condition.await();
            for (int i = 0; i < 5; i++) {
                System.out.println("ThreadName=" + Thread.currentThread().getName()
                        + (" " + (i + 1)));
            }
        } catch (InterruptedException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
        finally
        {
            lock.unlock();
        }
    }
}

Condition 的 await() 会阻塞当前线程,并释放锁、signal() 方法唤醒 wait 阻塞的线程。

Condition.awiat() = Object.wait()
Condition.signal() = Object.notify()
Condition.signalAll() = Object.notifyAll()

reentrantLock 和 condition 都是成对出现,一个 reentrantLock 里面可以有多个 condition 阻塞条件对象,需要知道的是 conditionA await 阻塞的线程对象会放在这个 conditionA 的阻塞队列里,也只能由 conditionA signalAll 唤醒。换一个 condition 对象 conditionB 是不管用的

线程池的阻塞队列里面大量使用了 reentrantLock ,condition ,一般我们直接用 reentrantLock 、 condition 的时候比较少,虽然 reentrantLock 的性能比 synchronized 要好,但是在使用上没有 synchronized 方便啊,synchronized 关键字乙方就完了,我们就不用管了。不过 reentrantLock 、 condition 的 API 我们要熟,很多时候看别人的代码时会用到。

ReentrantLock类的方法


  • getHoldCount()
    查询当前线程保持此锁的次数,也就是执行此线程执行lock方法的次数

  • getQueueLength()
    返回正等待获取此锁的线程估计数,比如启动10个线程,1个线程获得锁,此时返回的是9

  • getWaitQueueLength(Condition condition)
    返回等待与此锁相关的给定条件的线程估计数。比如10个线程,用同一个condition对象,并且此时这10个线程都执行了condition对象的await方法,那么此时执行此方法返回10

  • hasWaiters(Condition condition)
    查询是否有线程等待与此锁有关的给定条件(condition),对于指定contidion对象,有多少线程执行了condition.await方法

  • hasQueuedThread(Thread thread)
    查询给定线程是否等待获取此锁

  • hasQueuedThreads()
    是否有线程等待此锁

  • isFair()该锁是否公平锁

  • isHeldByCurrentThread() 当前线程是否保持锁锁定,线程的执行lock方法的前后分别是false和true

  • isLock()
    此锁是否有任意线程占用

  • lockInterruptibly()
    如果当前线程未被中断,获取锁

  • tryLock()
    尝试获得锁,仅在调用时锁未被线程占用,获得锁

  • tryLock(long timeout TimeUnit unit)
    如果锁在给定等待时间内没有被另一个线程保持,则获取该锁

Lock类分公平锁和不公平锁,公平锁是按照加锁顺序来的,非公平锁是不按顺序的,也就是说先执行lock方法的锁不一定先获得锁

reentrantLock 的确要灵活的多,我们不用使用别的锁了,在想要的位置直接 new 一把锁,阻塞的条件可以有多个,可以实现复杂的操作,这是阻塞队列的核心。另外 reentrantLock 可以使用 tryLock 尝试获得锁,可以避免一直卡在这里竞争锁。reentrantLock 对于高玩来说是个可以极大发挥的东西,但是对于 coder 们来说,还是在项目纵谨慎使用。

下面是一个对 ReentrantLock 中肯的评价

既然如此,我们什么时候才应该使用 ReentrantLock 呢?答案非常简单 —— 在确实需要一些 synchronized 所没有的特性的时候,比如时间锁等候、可中断锁等候、无块结构锁、多个条件变量或者锁投票。 ReentrantLock 还具有可伸缩性的好处,应当在高度争用的情况下使用它,但是请记住,大多数 synchronized 块几乎从来没有出现过争用,所以可以把高度争用放在一边。我建议用 synchronized 开发,直到确实证明 synchronized 不合适,而不要仅仅是假设如果使用 ReentrantLock “性能会更好”。请记住,这些是供高级用户使用的高级工具。(而且,真正的高级用户喜欢选择能够找到的最简单工具,直到他们认为简单的工具不适用为止。)。一如既往,首先要把事情做好,然后再考虑是不是有必要做得更快。

参考资料:


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

推荐阅读更多精彩内容

  • 作者: 一字马胡 转载标志 【2017-11-03】 更新日志 前言 在java中,锁是实现并发的关键组件,多个...
    一字马胡阅读 44,143评论 1 32
  •  既然java内置了synchronized,为什么还要出现lock呢? 由于synchronized的并发是阻塞...
    扈扈哈嘿阅读 888评论 0 1
  • Java-Review-Note——4.多线程 标签: JavaStudy PS:本来是分开三篇的,后来想想还是整...
    coder_pig阅读 1,629评论 2 17
  • PCA 算法主要是把高维度的数据降为低维度数据。典型地应用包括数据压缩和数据可视化。本文介绍 PCA 算法及其典型...
    kamidox阅读 4,941评论 6 12
  • 1 在佛山学习了6天,今天决定回去,上午10:30看票,最合适的13:50广州到长沙,历经7小时22分(还是要省学...
    橘子778阅读 214评论 0 2