栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

什么是锁?(未优化,不好读懂)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

什么是锁?(未优化,不好读懂)

什么是锁呢?
我搜集到的资料里表明,锁是一个内存中的···值?
如果这个值是0,就代表没人加锁。如果值是1,就代表有人加锁。

但想要正确地实现锁(使用锁?),需要注意两方面问题。
一方面是原子操作,另一方面是内存重排序。

首先是原子操作问题。
把内存中的一个值变成1或者0,设计多次操作。在x86平台上,大概有读取数据到寄存器、修改、写寄存器的值到内存。这是不原子的。
x86是缓存一致的,保证(只保证)操作一个缓存行内的数据是原子的。

其次是内存重排序问题。
内存重排序的基本原则是,单线程情况下程序必须看不出来做过重排序。
但在多线程下,就不能保证了。这需要借助内存模型。Java肯定是有的。

所以,想要正确的锁,我们需要解决内存重排序和原子操作问题。lock前缀+指令(锁内存总线)可以正确地实现原子CAS。

自旋锁的问题

太浪费cpu了。
有的时候我们需要让线程挂起。这类操作其实有对应的系统调用------futex。
futex就是那种,拿到锁就进入临界区,拿不到就挂起的机制。

Java等语言会在用户态实现一个futex的变体,如AQS队列。它们可能是混血的,尝试CAS几次,如果失败了,再futex(需要变态,比较重,因此我们尽量不futex)。这种机制很聪明。

这种思想不光可以用在线程上,还可以用在routine上。因为挂起线程的操作很重,所以我们有了混血futex。但对于routine,让他在用户态睡眠是ok的。这不需要变态。事实上golang的信号量就是这么实现的。

但是golang的semaphore问题可能会导致协程频繁的唤醒、抢锁失败、挂起。这会导致大量的协程做没用事情,甚至饿死。

为了解决这个问题,golang实现了mutex。mutex既有spin,又有semaphore,还有另一层实现。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/771108.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号