最全12张图带你彻底理解Java中的各种锁,阿里巴巴蚂蚁金服2024金融核心部门实习面经

学习分享,共勉

这里是小编拿到的学习资源,其中包括“中高级Java开发面试高频考点题笔记300道.pdf”和“Java核心知识体系笔记.pdf”文件分享,内容丰富,囊括了JVM、锁、并发、Java反射、Spring原理、微服务、Zookeeper、数据库、数据结构等大量知识点。同时还有Java进阶学习的知识笔记脑图(内含大量学习笔记)!

资料整理不易,读者朋友可以转发分享下!

Java核心知识体系笔记.pdf

记一次蚂蚁金服Java研发岗的面试经历,分享下我的复习笔记面经

中高级Java开发面试高频考点题笔记300道.pdf

记一次蚂蚁金服Java研发岗的面试经历,分享下我的复习笔记面经

架构进阶面试专题及架构学习笔记脑图

记一次蚂蚁金服Java研发岗的面试经历,分享下我的复习笔记面经

Java架构进阶学习视频分享

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

既然提到了CAS,这个也是面试高频问题,这里便将 CAS 做个简单介绍,可以将乐观锁和 CAS 二者联系起来理解。

CAS 是一种乐观锁实现机制,主要是三部分:内存值+旧的预期值+要修改的值。每次修改数据先比较内存中值与预期值是否相同,不同就自选,相同才修改。实现依靠unsafe(里面全是native修饰的本地方法,可以直接调用操作系统)+lock cmpxchg(底层依靠硬件指令)。

如图,原本共享变量 old value=0 ,线程修改数据先比较内存中的值是否为0,若为0,代表没有线程占用,此时才修改为 new value=1,当其他线程到达,发现内存值与 old value 不一样了,便自旋等待。

CAS缺点:

  • 可能造成ABA (version)问题——当一个值从A被更新为B,然后又改回来,普通 CAS 机制发现不了。

  • 一直 while 浪费资源:若并发量高,许多线程反复尝试更新变量又更新不成功,循环往复,会给 CPU 带来高消耗。

  • 不能保证代码块原子性:只能保证一个变量的原子操作,代码块要用 sychronized。

乐观锁与悲观锁的使用场景

这两种锁各有自己的优缺点,只有在合适的场景使用合适的锁,才能将各自的优势最大化体现出来。

乐观锁适用于读多写少的场景,因为它是不加锁的,相较于悲观锁不用加锁、释放锁,节省了开销。但是若写的多,冲突严重,可能导致线程一直 while 自旋,浪费资源,反而降低了性能。此时在这种写多读少的场景使用悲观锁就更合适。

独占锁和共享锁

=======

独占锁

===

独享锁也叫排他锁,是指该锁一次只能被一个线程所持有。如果线程T对数据A加上排它锁后,则其他线程不能再对A加任何类型的锁。获得排它锁的线程即能读数据又能修改数据。JDK 中的 synchronized 和 JUC 中 Lock 的实现类就是互斥锁。

共享锁

===

共享锁是指该锁可被多个线程所持有。如果线程T对数据A加上共享锁后,则其他线程只能对A再加共享锁,不能加排它锁。获得共享锁的线程只能读数据,不能修改数据。

需要注意的是,对于Java ReentrantLock 而言,其是独享锁。但是对于 Lock 的另一个实现类 ReadWriteLock,其读锁是共享锁,其写锁是独占锁。

读锁的共享锁可保证并发读是非常高效的,读写,写读,写写的过程是互斥的。

独占锁与共享锁也是通过 AQS 来实现的,通过实现不同的方法,来实现独享或者共享。

对于 synchronized 而言,当然是独占锁。

公平锁和非公平锁

========

公平锁

===

公平锁 是指多个线程按照申请锁的顺序来获取锁,线程直接进入队列中排队,队列中的第一个线程才能获得锁。

公平锁的优点是等待锁的线程不会饿死。缺点是整体吞吐效率相对非公平锁要低,等待队列中除第一个线程以外的所有线程都会阻塞,CPU唤醒阻塞线程的开销比非公平锁大。

非公平锁

====

非公平锁 是多个线程加锁时直接尝试获取锁,获取不到才会到等待队列的队尾等待。但如果此时锁刚好可用,那么这个线程可以无需阻塞直接获取到锁,所以非公平锁有可能出现后申请锁的线程先获取锁的场景。

非公平锁的优点是可以减少唤起线程的开销,整体的吞吐效率高,因为线程有几率不阻塞直接获得锁,CPU不必唤醒所有线程。缺点是处于等待队列中的线程可能会饿死,或者等很久才会获得锁。

在Java中 synchronized 是非公平锁,ReentrantLock 可以是非公平锁,也可以是公平锁,默认非公平锁。

//此处创建一个非公平锁,默认就是非公平,true 表示公平,false 表示公平。

Lock lock =new ReentrantLock(flase);

此处既然谈到了 synchronized和 ReentrantLock,那么,便顺便与Lock联系起来做个简单的对比。

  • 来源:synchronized 是关键字,lock是一个接口,实现类进行锁操作。

  • 是否知道获取锁:synchronized 无法判断锁的状态,lock 可以判断是否获得锁 (boolean b =lock.tryLock();)

  • 是否释放锁:synchronized 自动释放锁,lock 手动释放(容易死锁) lock.unlock();synchronized 阻塞后,其他线程一直等待,lock有超时时间。

  • synchronized 可重入锁(多次获取同一把锁),不可中断,非公平锁;lock,默认为非公平锁,可设置为公平。

  • 调度机制:synchronized 使用 Object 对象本身的 wait 、 notify、notifyAll 调度机制,而 Lock 可以使用 Condition 进行线程之间的调度。

  • 是否响应中断:lock 等待锁过程中可以用 interrupt 来中断等待,而 synchronized 只能等待锁的释放,不能响应中断。

分段锁

===

分段锁其实是一种锁的设计,并不是具体的一种锁,具体在 ConcurrentHashMap JDK1.7 版本有所体现。其并发的实现就是通过分段锁的形式来实现高效的并发操作。

何为分段锁?为何引入分段锁?

不妨同 Hashtable 进行比较,我们都知道 Hashtable 是并发安全的,但是它的效率却很低下,因为它将整个表都锁起来了。这样就使得很大程度降低了性能。而 ConcurrentHashMap JDK1.7 引入了分段锁。

一个 Segment 就相当于一把锁,它只锁住这个槽位,其他的并不受影响。ConcurrentHashMap 将 hash 表分为 16 个桶(默认值),诸如get,put,remove 等常用操作只锁当前需要用到的桶。

试想,原来 只能一个线程进入,现在却能同时16个写线程进入(写线程才需要锁定,而读线程几乎不受限制,之后会提到),并发性的提升是显而易见的。

ConcurrentHashMap JDK1.7 中 数据结构是由 Segment 数组+ HashEntry 数组+链表组成的。

Segment 继承了 ReentrantLock,一个 Segment[i] 就是一把分段锁。比起 Hashtable 锁粒度更细,性能更高。

一个Segment中包含一个HashEntry数组,每个HashEntry又是一个链表结构

static final class Segment<K,V> extens ReentrantLock implements Serializable{

transient volatile HashEntry<K,V>[] tables;

//…

结语

小编也是很有感触,如果一直都是在中小公司,没有接触过大型的互联网架构设计的话,只靠自己看书去提升可能一辈子都很难达到高级架构师的技术和认知高度。向厉害的人去学习是最有效减少时间摸索、精力浪费的方式。

我们选择的这个行业就一直要持续的学习,又很吃青春饭。

虽然大家可能经常见到说程序员年薪几十万,但这样的人毕竟不是大部份,要么是有名校光环,要么是在阿里华为这样的大企业。年龄一大,更有可能被裁。

送给每一位想学习Java小伙伴,用来提升自己。

在这里插入图片描述

本文到这里就结束了,喜欢的朋友可以帮忙点赞和评论一下,感谢支持!

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

以帮忙点赞和评论一下,感谢支持!

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值