继续面试大纲系列文章。

  这是多线程的第二篇。

  多线程就像武学中对的吸星大法,理解透了用好了可以得道成仙,俯瞰芸芸众生;而滥用则会遭其反噬。

  在多线程编程中要渡的第二个“劫”,则是Lock。在很多时候,包括面试、包括实际项目应用,我们都会拿来和synchronized对比一番。

  我们知道,多线程的核心思想是通过增加线程数量来并发的运行,来提高效率,也就是数量决胜论,而不是质量决胜(提高每个线程的处理能力)。多线程编程中面临的最大挑战,是如何解决多个线程同时修改一个公用的变量所带来的变量值不确定性问题。顺着这个思路分析,常用办法,无非就是,要么对变量动手,在一个线程修改时,变量值被锁定。要么是对修改的操作动手,在该段代码执行时,对其加锁,其他线程不可以在同一时刻进入该段代码执行。

  同synchronized一样,Lock,也是实现了后一种办法。只不过,实现方式,有所不同。

Lock

  1. 问:你平时涉及到多线程编程多不多?谈谈你对Lock锁的理解
  2. 分析:最好对比着synchronized来讲
  3. 答:
    1.   在多线程编程中,为了达到线程安全的目的,我们往往通过加锁的方式来实现。Lock锁是java代码级别来实现的,相对于synchronizedd在功能性上,有所加强,主要是,公平锁,轮询锁,定时锁,可中断锁等,还增加了多路通知机制(Condition),可以用一个锁来管理多个同步块。另外在使用的时候,必须手动的释放锁。
    2. 详细分析:
      1. Lock锁的实现,主要是借助于队列同步器(我们常常见到的AQS)来实现。它包括一个int变量来表示状态;一个FIFO队列,来存储获取资源的排队线程。
      2. 当一个线程申请资源时,就是是获取当前的同步状态,并判断是否可符合预期,如果是,则通过CAS操作,来修改上述Int变量标识的同步状态。如果否,则线程进入队列排队(这是在一般情况,在使用tyrLock时,是直接返回获取锁失败)。
          1. 锁有独占锁和共享锁。独占锁就是在同一时刻,只允许同一个线程持有该锁;共享锁实现的时候和独占锁稍有不同,不是简单的修改同步状态(比如1和0),而是获取这个值,当值大于0时,即标识获取共享锁成功(隐含意思是每个线程获取锁成功后,这个值减1)。这里附上独占锁的实现源码(源码片段来自《java并发编程的艺术》,并加上自己的注释):

            public class Mutex implements Lock {  
            
                // 静态内部类,自定义同步器
            private static class Sync extends AbstractQueuedSynchronizer{
            // 该方法用于判断当前锁是否在独占模式下被占用状态
            protected boolean isHeldExclusively(){
            return getState() == 1;
            } // 获取锁!!!
            public boolean tryAcquire(int acquires){
                  //典型的CAS原子操作,如果初始状态为0,可以获得锁
            if (compareAndSetState(0, 1)){
            setExclusiveOwnerThread(Thread.currentThread());
            return true;
            }
            return false;
            } //释放锁,将当前状态设置为0
            protected boolean tryRelease(int releases){
            if (getState() == 0){
            throw new IllegalMonitorStateException();
            }
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
            } // 返回一个Condition,每个condition都包含了一个condition队列 ,这个后续再说
            Condition newCondition(){
            return new ConditionObject();
            }
            }
      3. Lock锁中,支持可中断的锁,实现原理是,队列中的等待线程,可以响应其他线程发起的中断信号,抛出InterruptdException异常。
      4. 关于同步队列,需要了解,获取同步状态失败的线程,被包装为Node节点后,加入队列尾,这个操作是CAS操作,以保证线程安全,失败就死循环重试;而队列首节点,则是当前持有锁的线程。该节点一旦释放锁,会唤醒后继节点。
      5. 关于唤醒,是这样的,每个在同步队列中的阻塞线程,都处于自旋的状态,不断的尝试获取锁。这样,当首节点释放锁唤醒后继线程后,被唤醒的线程,还需要判断是否前继线程是首线程,是则获取同步状态(锁)成功。

  4.扩展:Condition,多路通知机制  

  

  1. 在Synchronized锁中,提供了wait、notify、notifyAll等方法,实现了等待/通知模式。那么在lock中,由Condition配合,也实现了类似的模式。
  2. 其实现实质是,一个Condition包含一个等待队列,定义多个Condition,那就有多个等待队列,和上文提到的同步队列配合使用。同步队列-等待队列模型请参考下图:
  3. 在上述模型中,调用await方法,相当于把同步队列首节点(持有锁的线程),移动到等待队列。调用signal方法唤醒阻塞的线程,则是将对应Condition等待队列里的首节点(等待时间最长),移入同步队列。
  4. 还有一点需要补充,就是线程的唤醒,调用signal可以正常唤醒;在其他线程中终止线程,也一样会唤醒,只不过唤醒后,只是抛出InterruptException异常。
  5. 如果你看的爽,请点击右下角的“推荐”,是对小端坚持分享原创的最大鼓励。也可以关注小端的个人公众号 :   pnxsxb  ,会分享更多的原创技术文章。

欢迎扫描以下二维码关注公众号:小端有话说:

BAT美团滴滴java面试大纲(带答案版)之三:多线程Lock的更多相关文章

  1. BAT美团滴滴java面试大纲(带答案版)之三:多线程synchronized

    继续面试大纲系列文章. 从这一篇开始,我们进入ava编程中的一个重要领域---多线程!多线程就像武学中对的吸星大法,理解透了用好了可以得道成仙,俯瞰芸芸众生:而滥用则会遭其反噬. 在多线程编程中要渡的 ...

  2. 金三银四跳槽季,BAT美团滴滴java面试大纲(带答案版)之一:Java基础篇

    Java基础篇: 题记:本系列文章,会尽量模拟面试现场对话情景, 用口语而非书面语 ,采用问答形式来展现.另外每一个问题都附上“延伸”,这部分内容是帮助小伙伴们更深的理解一些底层细节的补充,在面试中可 ...

  3. BAT美团滴滴java面试大纲(带答案版)之四:多线程Lock

    每天学习一点点 编程PDF电子书.视频教程免费下载:http://www.shitanlife.com/code 这是多线程的第二篇. 多线程就像武学中对的吸星大法,理解透了用好了可以得道成仙,俯瞰芸 ...

  4. Java面试大纲-java面试该做哪些准备,java开发达到这样的水平可以涨工资

    Java培训结束,面临的就是毕业找工作.在找工作时,就要针对性地做充分的面试准备.准备不充分的面试,完全是浪费时间,更是对自己的不负责. 上海尚学堂Java培训整理出Java面试大纲,其中大部分都是面 ...

  5. 2019滴滴java面试总结 (包含面试题解析)

    2019滴滴java面试总结  (包含面试题) 本人6年开发经验.今年年初找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.滴滴等公司offer,岗位是既有php也有Java后端开发,最终选择去了滴滴 ...

  6. Java面试宝典(2018版)

    置顶 2018年11月10日 23:49:18 我要取一个响亮的昵称 阅读数:8893    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/chen ...

  7. Java面试:投行的15个多线程和并发面试题

    多线程和并发问题已成为各种 Java 面试中必不可少的一部分.如果你准备参加投行的 Java 开发岗位面试,比如巴克莱银行(Barclays).花旗银行(Citibank).摩根史坦利投资公司(Mor ...

  8. Java面试:投行的15个多线程和并发面试题(转)

    多线程和并发问题已成为各种 Java 面试中必不可少的一部分.如果你准备参加投行的 Java 开发岗位面试,比如巴克莱银行(Barclays).花旗银行(Citibank).摩根史坦利投资公司(Mor ...

  9. 2019 滴滴java面试笔试总结 (含面试题解析)

       本人5年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.滴滴等公司offer,岗位是Java后端开发,因为发展原因最终选择去了滴滴,入职一年时间了,也成为了面试官, ...

随机推荐

  1. 关于better-scroll中的问题点

    最近在学习vue和better-scroll结合开发音乐APP,看着视频介绍中在制作slidet轮播图的时候,视频中讲解要想实现无缝滚动,则加入snapLoot:true,但是不可以单独引入它,必须将 ...

  2. Java设计模式-合成模式

    合成模式有时也叫组合模式,对象组合成树形结构以表示"部分-整体"的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性.掌握组合模式的重点是要理解清楚 "部分/ ...

  3. MySQL详解--锁,事务

    http://www.cnblogs.com/jukan/p/5670950.html http://blog.csdn.net/xifeijian/article/details/20313977 ...

  4. 1077. Kuchiguse (20)

    The Japanese language is notorious for its sentence ending particles. Personal preference of such pa ...

  5. Nginx阻止对不明确主机名的请求

    在用户请求头中,有可能会有Host行不明确的情况,如果不想处理这类用户请求,那么可以定义一个默认的server来丢弃这类请求.例如 server{ listen default_server; ser ...

  6. MySQL升级-5.6升级到5.7版本&切换GTID模式

          目前未在生产环境中升级过数据库版本,倒是在测试环境跟开发环境升级过.       可以通过mysqldump sql文件进行升级,也可以通过mysql_upgrade升级,前者耗时较长,且 ...

  7. <经验杂谈>C#对CA证书加密解密的简单介绍

    最近做项目接触了一些关于用CA证书加密解密的知识,现在分享一下,加密主要分为对称加密和非对称加密以及单项加密这三种,CA是一个权威的第三方认证机构,CA加密有公钥和私钥之分. 以下是C#读取证书文件进 ...

  8. java中使用ReentrantLock锁中的Condition实现三个线程之间通信,交替输出信息

    本文直接附上源代码,如下是自己写的一个例子 面试题需求: 使用Condition来实现 三个线程 线程1 线程2 线程3 三个交替输出 [按照 线程1(main)-->线程2-->线程3] ...

  9. oracle导入dmp文件的2种方法

    使用imp.impdp方式导入数据 1.使用imp导入数据 打开cmd窗口,然后直接敲入一下命令即可,需要注意的是,要事先把dmp文件放到正确的路径中去 imp yx_base/@yx_192. fi ...

  10. Beta No.1

    一.今日任务 重新熟悉整体项目 对整个项目在未来的beta冲刺中进程有一个合理的规划 由于我们送出的是一个负责前端的成员,引入的也是一个负责前端工作的女生,(女生做起美工比起男生更加得心应手吧)所以我 ...