[Java的架构师技术栈]面试官:如何实现一个乐观锁(小白都能看得懂的代码)
java多线程中的锁分类多种多样 , 其中有一种主要的分类方式就是乐观和悲观进行划分的 。 这篇文章主要介绍如何自己手写一个乐观锁代码 。 不过文章为了保证完整性 , 会从基础开始介绍 。
一、乐观锁概念说是写乐观锁的概念 , 但是通常乐观锁和悲观锁的概念都要一块写 。 对比着来才更有意义 。
1、悲观锁概念
【[Java的架构师技术栈]面试官:如何实现一个乐观锁(小白都能看得懂的代码)】悲观锁:总是假设最坏的情况 , 每次去拿数据的时候都认为别人会修改 , 所以每次在拿数据的时候都会上锁 , 这样别人想拿这个数据就会阻塞 , 直到它拿到锁 。
文章图片
就比如说java里面的同步机制synchronized关键字就是一个悲观锁 , 当一个变量或者是方法使用了synchronized修饰时 , 其他的线程想要拿到这个变量或者是方法的时候将就需要等到别的线程释放 。
数据库里面也用到了这种悲观锁的机制 。 比如行锁 , 表锁等 , 读锁 , 写锁等 , 都是在做操作之前先上锁 。 这样其他的线程就不能同步操作 , 必须要等到他释放才可以 。
2、乐观锁概念
乐观锁:总是假设最好的情况 , 每次去拿数据的时候都认为别人不会修改 , 所以不会上锁 , 只在更新的时候会判断一下在此期间别人有没有去更新这个数据 。
文章图片
注意“在此期间”的含义是拿到数据到更新数据的这段时间 。 因为没有加锁 , 所以别的线程可能会更改 。 还有一点那就是乐观锁其实是不加锁的 。
今天我们要实现的就是一个乐观锁机制 , 既然乐观锁是不加锁的 , 而且还要保证数据的一致性 。 如何来实现呢?举个例子:java中的Atomic包下的一系列类就是使用了乐观锁机制 。 我们挑出来一个看看官方是如何实现的 , 然后按照这样的实现机制我们自己就可以实现 。
3、乐观锁实现案例
java并发机制中主要有三个特性需要我们去考虑 , 原子性、可见性和有序性 。 AtomicInteger的作用就是为了保证原子性 。 如何保证原子性呢?我们使用案例说明:
文章图片
这个例子很简单:我们定义了一个变量a , 初始值是0 , 然后使用5个线程去增加 , 每个线程增加10 , 按道理来说5个线程一共增加了50 , 但是运行一下就知道答案不到50 , 原因就在于里面那个加一操作:a++;
对于a++的操作 , 其实可以分解为3个步骤 。
(1)从主存中读取a的值
(2)对a进行加1操作
(3)把a重新刷新到主存
比如说有的线程已经把a进行了加1操作 , 但是还没来得及重刷入到主存 , 其他的线程就重新读取了旧值 。 这才造成了错误 。 解决办法就可以使用AtomicInteger:
文章图片
现在我们使用AtomicInteger定义a , 然后使用incrementAndGet进行自增操作 , 最后的结果就总是50了 。 为了什么AtomicInteger有这样的特点呢?我们来分析一下:
4、乐观锁案例分析
AtomicInteger是一个乐观锁 , 也就是说我们只要看一下AtomicInteger是如何实现这样的机制和原理 , 我们就可以找出其他乐观锁实现的一般机制 。 想要找出来答案我们还要从AtomicInteger的incrementAndGet方法说起 。 因为这个方法实现了锁一样的功能 。 这里使用的是jdk1.8的版本 , 不同的版本会有出入 。
文章图片
这里我们可以看到自增操作主要是使用了unsafe的getAndAddInt方法 。 因为不是专门介绍AtomicInteger , 所以不会对源码进行相信的分析 。
- 海南师范大学海南省科学技术厅谢京厅长一行赴我校调研指导重点实验室建设工作
- SENSORO升哲科技需要物联网技术来寻找新的增长点,后疫情时代下的零售业
- 申耀的科技观察如何重塑现代基础架构?,后疫情时代
- 中国财富网半导体显示技术前景广阔,134家机构调研TCL科技
- 小谢娱乐哦引来广大网友狂点赞,直呼炸天,程序员用Java实现扫雷小游戏
- 改造内容@鼓励集中连片整体改造,湖南发布城镇老旧小区改造技术导则
- 前哨迷彩搭载智能语音操作系统,战时输出全靠喊!,歼20又一技术曝光
- [炒股]那么多炒股的.他凭什么能赚,今年2W炒股。以赚4000。分享每天一个小技术
- 半导体投资联盟国产海光X86处理器开始技术迭代,7nm年底试流片
- 科学技术宅苹果12P强势来袭!,1200万像素四摄镜头+120Hz屏幕