【你好面试官】011 Java并发之锁的底层原理详解

微信公众号:你好面试官
这里没有碎片化的知识,只有完整的知识体系。
专注于系统全面的知识点讲解,面试题目解析;
如果你觉得文章对你有帮助,欢迎关注、分享、赞赏

###前言
二蛋几天没有收到面试通知,以为自己已经凉凉,没想到此时再次接到了面试邀请,于是在一个风和日丽的下午,二蛋如约坐在了面试官对面,开始了今天的面试。

面试官:小伙子,咱也不用继续介绍了,你也来了几次了,这次咱就开门见山吧。

###正文

介绍一下什么是锁?

锁是用来控制多个线程访问共享资源的方式,一般来说,一个锁能够防止多个线程同时 访问共享资源(但是有些锁可以允许多个线程并发的访问共享资源,比如读写锁)。在Lock接口出现之前,Java程序是靠synchronized关键字实现锁功能的,而Java SE 5之后,并发包中新增了Lock接口(以及相关实现类)用来实现锁功能,它提供了与synchronized关键字类似的同步功能,只是在使用时需要显式地获取和释放锁。虽然它缺少了(通过synchronized块或者方法所提供的)隐式获取释放锁的便捷性,但是却拥有了锁获取与释放的可操作性、可中断的获取锁以及超时获取锁等多种synchronized关键字所不具备的同步特性。

使用synchronized关键字将会隐式地获取锁,但是它将锁的获取和释放固化了,也就是先获取再释放。当然,这种方式简化了同步的管理,可是扩展性没有显示的锁获取和释放来的好。例如,针对一个场景,手把手进行锁获取和释放,先获得锁A,然后再获取锁B,当锁B获得后,释放锁A同时获取锁C,当锁C获得后,再释放B同时获取锁D,以此类推。这种场景下,synchronized关键字就不那么容易实现了,而使用Lock却容易许多。

Lock是一个接口,它定义了锁获取和释放的基本操作。

锁的底层原理是如何实现的?

锁的实现机制主要依赖于队列同步器,它使用了一个int成员变量表示同步状态,通过内置的FIFO队列来完成资源获取线程的排队工作,能够实现大部分的同步需求。

同步器包含两个节点类型的应用,一个指向头节点,一个指向尾节点,未获取到锁的线程会创建节点线程安全(compareAndSetTail)的加入队列尾部。同步队列遵循FIFO,首节点是获取同步状态成功的节点。

未获取到锁的线程将创建一个节点,设置到尾节点。如下图所示:

首节点的线程在释放锁时,将会唤醒后继节点。而后继节点将会在获取锁成功时将自己设置为首节点。如下图所示:

独占式与响应式锁的获取

  • 独占式:有且只有一个线程能获取到锁。
  • 共享式:可以多个线程同时获取到锁。

独占式:每个节点自旋观察自己的前一节点是不是Header节点,如果是,就去尝试获取锁。

独占式锁获取流程:

共享式与独占式的区别:

共享锁获取流程:

面试官:嗯,今天的面试就到这里吧,回去好好准备下一次面试吧。



这里没有碎片化的知识,只有完整的知识体系。
专注于系统全面的知识点讲解,面试题目解析;
如果你觉得文章对你有帮助,欢迎关注、分享、赞赏

发布了97 篇原创文章 · 获赞 47 · 访问量 14万+

猜你喜欢

转载自blog.csdn.net/Momentyol/article/details/104520159