Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
沉默王二
Jmx Java
提交
4dbf9259
J
Jmx Java
项目概览
沉默王二
/
Jmx Java
大约 1 年 前同步成功
通知
160
Star
18
Fork
2
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
J
Jmx Java
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
4dbf9259
编写于
8月 30, 2023
作者:
沉默王二
💬
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
AQS
上级
1d1dbced
变更
7
展开全部
隐藏空白更改
内联
并排
Showing
7 changed file
with
251 addition
and
140 deletion
+251
-140
README.md
README.md
+2
-2
docs/home.md
docs/home.md
+2
-2
docs/overview/readme.md
docs/overview/readme.md
+1
-1
docs/thread/aqs.md
docs/thread/aqs.md
+124
-15
docs/thread/cas.md
docs/thread/cas.md
+19
-17
docs/thread/pianxiangsuo.md
docs/thread/pianxiangsuo.md
+101
-101
docs/thread/synchronized.md
docs/thread/synchronized.md
+2
-2
未找到文件。
README.md
浏览文件 @
4dbf9259
...
...
@@ -253,8 +253,8 @@
-
[
Java的内存模型(JMM)
](
docs/thread/jmm.md
)
-
[
volatile关键字解析
](
docs/thread/volatile.md
)
-
[
synchronized关键字解析
](
docs/thread/synchronized-1.md
)
-
[
synchronized
锁的到底是什么?
](
docs/thread/synchronized.md
)
-
[
JDK15 移除了
偏向锁
](
docs/thread/pianxiangsuo.md
)
-
[
synchronized
的四种锁状态
](
docs/thread/synchronized.md
)
-
[
深入浅出
偏向锁
](
docs/thread/pianxiangsuo.md
)
-
[
CAS详解
](
docs/thread/cas.md
)
-
[
AQS详解
](
docs/thread/aqs.md
)
-
[
锁分类及 JUC 包下的那些锁
](
docs/thread/lock.md
)
...
...
docs/home.md
浏览文件 @
4dbf9259
...
...
@@ -262,8 +262,8 @@ head:
-
[
Java的内存模型(JMM)
](
thread/jmm.md
)
-
[
volatile关键字解析
](
thread/volatile.md
)
-
[
synchronized关键字解析
](
thread/synchronized-1.md
)
-
[
synchronized
锁的到底是什么?
](
thread/synchronized.md
)
-
[
JDK15 移除了
偏向锁
](
thread/pianxiangsuo.md
)
-
[
synchronized
的四种锁状态
](
thread/synchronized.md
)
-
[
深入浅出
偏向锁
](
thread/pianxiangsuo.md
)
-
[
CAS详解
](
thread/cas.md
)
-
[
AQS详解
](
thread/aqs.md
)
-
[
锁分类及 JUC 包下的那些锁
](
thread/lock.md
)
...
...
docs/overview/readme.md
浏览文件 @
4dbf9259
...
...
@@ -20,7 +20,7 @@ head:
-
小册名字:二哥的 Java 进阶之路
-
小册作者:沉默王二
-
小册品质:能在 GitHub 取得 9
000+ star 自认为品质是有目共睹的
,尤其是国内还有不少小伙伴在访问 GitHub 的时候很不顺利。
-
小册品质:能在 GitHub 取得 9
200+ star,品质可以说是有目共睹
,尤其是国内还有不少小伙伴在访问 GitHub 的时候很不顺利。
-
小册风格:通俗易懂、风趣幽默、深度解析,新手可以拿来入门,老手可以拿来进阶,重要的知识,比如说面试高频的内容会从应用到源码挖个底朝天,还会穿插介绍一些计算机底层知识,力求讲个明白)
-
小册简介:这是一份通俗易懂、风趣幽默的Java学习指南,内容涵盖Java基础、Java并发编程、Java虚拟机、Java面试等核心知识点。学Java,就认准二哥的Java进阶之路😄
-
小册品位:底部用了梵高 1889 年的《星空》(the starry night),绝美的漩涡星空,耀眼的月亮,宁静的村庄,还有一颗燃烧着火焰的巨大柏树,我想小册的艺术品位也是恰到好处的。
...
...
docs/thread/aqs.md
浏览文件 @
4dbf9259
...
...
@@ -9,20 +9,20 @@ tag:
head
:
-
-
meta
-
name
:
keywords
content
:
Java,并发编程,多线程,Thread,AQS
content
:
Java,并发编程,多线程,Thread,AQS
,抽象队列同步器
---
# 第十三节:抽象队列同步器 AQS
**AQS**
是
`AbstractQueuedSynchronizer`
的简称,即
`抽象队列同步器`
,从字面
意思上
理解:
**AQS**
是
`AbstractQueuedSynchronizer`
的简称,即
`抽象队列同步器`
,从字面
上可以这样
理解:
-
抽象:抽象类,只实现一些主要逻辑,有些方法由子类实现;
-
队列:使用先进先出(FIFO)队列存储数据;
-
队列:使用先进先出(FIFO)
的
队列存储数据;
-
同步:实现了同步的功能。
那 AQS 有什么用呢?
AQS 是一个用来构建锁和同步器的框架,使用 AQS 能简单且高效地构造出应用广泛的同步器,比如我们
提到的
[
ReentrantLock
](
https://javabetter.cn/thread/reentrantLock.html
)
,Semaphore,
[
ReentrantReadWriteLock
](
https://javabetter.cn/thread/ReentrantReadWriteLock.html
)
,SynchronousQueue,
[
FutureTask
](
https://javabetter.cn/thread/callable-future-futuretask.html
)
等等皆
是基于 AQS 的。
AQS 是一个用来构建锁和同步器的框架,使用 AQS 能简单且高效地构造出应用广泛的同步器,比如我们
后面会细讲的
[
ReentrantLock
](
https://javabetter.cn/thread/reentrantLock.html
)
,Semaphore,
[
ReentrantReadWriteLock
](
https://javabetter.cn/thread/ReentrantReadWriteLock.html
)
,SynchronousQueue,
[
FutureTask
](
https://javabetter.cn/thread/callable-future-futuretask.html
)
等等,都
是基于 AQS 的。
当然了,我们也可以利用 AQS 轻松定制专属的同步器,只要实现它的几个
`protected`
方法就可以了。
...
...
@@ -45,26 +45,26 @@ setState()
compareAndSetState
()
```
这三种操作均是原子操作,其中 compareAndSetState 的实现依赖于
Unsafe
的
`compareAndSwapInt()`
方法。
这三种操作均是原子操作,其中 compareAndSetState 的实现依赖于
[
Unsafe
](
https://javabetter.cn/thread/Unsafe.html
)
的
`compareAndSwapInt()`
方法。
AQS 内部使用了一个先进先出(FIFO)的
[
双端队列
](
https://javabetter.cn/collection/arraydeque.html
)
,并使用了两个指针 head 和 tail 用于标识队列的头部和尾部。其数据结构如下图所示:
![](
https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/thread/aqs-c294b5e3-69ef-49bb-ac56-f825894746ab.png
)
但它并不
是
直接储存线程,而是储存拥有线程的 Node 节点。
但它并不直接储存线程,而是储存拥有线程的 Node 节点。
![](
https://cdn.tobebetterjavaer.com/stutymore/aqs-20230805211157.png
)
##
资源共享模式
##
AQS 的 Node 节点
资源有两种共享模式,或者说两种同步方式:
-
独占模式(Exclusive):资源是独占的,一次只能有一个线程获取。如
[
ReentrantLock
](
https://javabetter.cn/thread/reentrantLock.html
)
。
-
共享模式(Share):同时可以被多个线程获取,具体的资源个数可以通过参数指定。如
Semaphore/
[
CountDownLatch
](
https://javabetter.cn/thread/CountDownLatch.html
)
。
-
独占模式(Exclusive):资源是独占的,一次只能有一个线程获取。如
[
ReentrantLock
](
https://javabetter.cn/thread/reentrantLock.html
)
(后面会细讲,戳链接直达)
。
-
共享模式(Share):同时可以被多个线程获取,具体的资源个数可以通过参数指定。如
[
Semaphore/CountDownLatch
](
https://javabetter.cn/thread/CountDownLatch.html
)
(戳链接直达,后面会细讲)
。
一般情况下,子类只需要根据需求实现其中一种模式就可以,当然也有同时实现两种模式的同步类,如
`ReadWriteLock`
。
一般情况下,子类只需要根据需求实现其中一种模式就可以,当然也有同时实现两种模式的同步类,如
[
ReadWriteLock
](
https://javabetter.cn/thread/ReentrantReadWriteLock.html
)
。
AQS 中关于这两种资源共享模式的定义源码
(均在内部类 Node 中)
。我们来看看 Node 的结构:
AQS 中关于这两种资源共享模式的定义源码
均在内部类 Node 中
。我们来看看 Node 的结构:
```
java
static
final
class
Node
{
...
...
@@ -111,9 +111,44 @@ private Node addWaiter(Node mode) {
}
```
注意:通过 Node 我们可以实现两个队列,一是通过 prev 和 next 实现 CLH 队列(线程同步队列、双向队列),二是 nextWaiter 实现 Condition 条件上的等待线程队列(单向队列),这个 Condition 主要用在 ReentrantLock 类中。
通过 Node 我们可以实现两种队列:
## AQS 的主要源码解析
1)一是通过 prev 和 next 实现 CLH(Craig, Landin, and Hagersten)队列(线程同步队列、双向队列)。
在 CLH 锁中,每个等待的线程都会有一个关联的 Node,每个 Node 有一个 prev 和 next 指针。当一个线程尝试获取锁并失败时,它会将自己添加到队列的尾部并自旋,等待前一个节点的线程释放锁。类似下面这样。
```
java
public
class
CLHLock
{
private
volatile
Node
tail
;
private
ThreadLocal
<
Node
>
myNode
=
ThreadLocal
.
withInitial
(
Node:
:
new
);
private
ThreadLocal
<
Node
>
myPred
=
new
ThreadLocal
<>();
public
void
lock
()
{
Node
node
=
myNode
.
get
();
node
.
locked
=
true
;
// 把自己放到队尾,并取出前面的节点
Node
pred
=
tail
;
myPred
.
set
(
pred
);
while
(
pred
.
locked
)
{
// 自旋等待
}
}
public
void
unlock
()
{
Node
node
=
myNode
.
get
();
node
.
locked
=
false
;
myNode
.
set
(
myPred
.
get
());
}
private
static
class
Node
{
private
volatile
boolean
locked
;
}
}
```
2)二是通过 nextWaiter 实现
[
Condition
](
https://javabetter.cn/thread/condition.html
)
(后面会细讲,戳链接直达)上的等待线程队列(单向队列),这个 Condition 主要用在
[
ReentrantLock
](
https://javabetter.cn/thread/reentrantLock.html
)
类中。
## AQS 的源码解析
AQS 的设计是基于
**模板方法模式**
的,它有一些方法必须要子类去实现的,它们主要有:
...
...
@@ -131,7 +166,7 @@ protected boolean tryAcquire(int arg) {
}
```
这里不使用抽象方法的目的是:避免强迫子类中把所有的抽象方法都实现一遍,减少无用功,这样子类只需要实现自己关心的抽象方法即可,比如
Semaphore
只需要实现 tryAcquire 方法而不用实现其余不需要用到的模版方法:
这里不使用抽象方法的目的是:避免强迫子类中把所有的抽象方法都实现一遍,减少无用功,这样子类只需要实现自己关心的抽象方法即可,比如
[
信号 Semaphore
](
https://javabetter.cn/thread/CountDownLatch.html
)
只需要实现 tryAcquire 方法而不用实现其余不需要用到的模版方法:
![](
https://cdn.tobebetterjavaer.com/stutymore/aqs-20230805211732.png
)
...
...
@@ -287,10 +322,84 @@ private void unparkSuccessor(Node node) {
## 小结
AQS 是一个用来构建锁和同步器的框架,使用 AQS 能简单且高效地构造出应用广泛的同步器,比如我们提到的
[
ReentrantLock
](
https://javabetter.cn/thread/reentrantLock.html
)
,
Semaphore
,
[
ReentrantReadWriteLock
](
https://javabetter.cn/thread/ReentrantReadWriteLock.html
)
,SynchronousQueue,
[
FutureTask
](
https://javabetter.cn/thread/callable-future-futuretask.html
)
等等皆是基于 AQS 的。
AQS 是一个用来构建锁和同步器的框架,使用 AQS 能简单且高效地构造出应用广泛的同步器,比如我们提到的
[
ReentrantLock
](
https://javabetter.cn/thread/reentrantLock.html
)
,
[
Semaphore
](
https://javabetter.cn/thread/CountDownLatch.html
)
,
[
ReentrantReadWriteLock
](
https://javabetter.cn/thread/ReentrantReadWriteLock.html
)
,SynchronousQueue,
[
FutureTask
](
https://javabetter.cn/thread/callable-future-futuretask.html
)
等等皆是基于 AQS 的。
当然了,我们也可以利用 AQS 轻松定制专属的同步器,只要实现它的几个
`protected`
方法就可以了。
来个互斥锁(同一时刻只允许一个线程持有锁)。
```
java
import
java.util.concurrent.locks.AbstractQueuedSynchronizer
;
public
class
Mutex
{
private
static
class
Sync
extends
AbstractQueuedSynchronizer
{
@Override
protected
boolean
tryAcquire
(
int
arg
)
{
if
(
compareAndSetState
(
0
,
1
))
{
setExclusiveOwnerThread
(
Thread
.
currentThread
());
return
true
;
}
return
false
;
}
@Override
protected
boolean
tryRelease
(
int
arg
)
{
if
(
getState
()
==
0
)
{
throw
new
IllegalMonitorStateException
();
}
setExclusiveOwnerThread
(
null
);
setState
(
0
);
return
true
;
}
@Override
protected
boolean
isHeldExclusively
()
{
return
getState
()
==
1
;
}
}
private
final
Sync
sync
=
new
Sync
();
public
void
lock
()
{
sync
.
acquire
(
1
);
}
public
void
unlock
()
{
sync
.
release
(
1
);
}
public
boolean
isLocked
()
{
return
sync
.
isHeldExclusively
();
}
}
```
上面的 Mutex 类是一个互斥锁。它内部使用了一个 Sync 类,该类继承自 AQS。
-
tryAcquire:尝试获取资源。如果当前状态为0(未锁定),那么设置为1(锁定),并设置当前线程为独占资源的线程。
-
tryRelease:尝试释放资源。设置状态为0并清除持有资源的线程。
-
isHeldExclusively:判断当前资源是否被独占。
假设有一个线程不安全的资源,我们需要确保在任何时刻只有一个线程能访问它,那么就可以使用这个 Mutex 锁来确保线程安全。
```
java
public
class
Resource
{
private
Mutex
mutex
=
new
Mutex
();
public
void
use
()
{
mutex
.
lock
();
try
{
// 对资源的操作
}
finally
{
mutex
.
unlock
();
}
}
}
```
在上述场景中,我们为一个不安全的资源添加了一个互斥锁,确保同一时刻只有一个线程可以使用这个资源,从而确保线程安全。
> 编辑:沉默王二,编辑前的内容来源于朋友开源的这个仓库:[深入浅出 Java 多线程](http://concurrent.redspider.group/),强烈推荐。值得参考文章:[君哥聊技术:2万字 + 40 张图带你精通 Java AQS](https://mp.weixin.qq.com/s/EWm7unc4lsXIv0iS3o12kg)
---
...
...
docs/thread/cas.md
浏览文件 @
4dbf9259
...
...
@@ -14,17 +14,17 @@ head:
# 第十二节:乐观锁 CAS
CAS(Compare-and-Swap)是一种
被广泛应用在并发控制中的算法,它是一种乐观锁的实现方式。CAS
全称为“比较并交换”,是一种无锁的原子操作。
CAS(Compare-and-Swap)是一种
乐观锁的实现方式,
全称为“比较并交换”,是一种无锁的原子操作。
在并发编程中,我们都知道
`i++`
操作是非线程安全的,这是因为
`i++`
操作不是原子操作,我们之前在讲
[
多线程带来了什么问题
](
https://javabetter.cn/thread/thread-bring-some-problem.html
)
中有讲到,大家应该还记得吧?
如何保证原子性呢?
常见的做法就是
`加锁`
。
常见的做法就是
加锁
。
在 Java 中,我们可以使用
[
synchronized
](
https://javabetter.cn/thread/synchronized-1.html
)
关键字 和
`CAS`
(Compare-and-Swap)来实现加锁效果。
`synchronized`
是悲观锁,尽管随着 JDK 版本的升级,synchronized 关键字已经“轻量级”了很多
,但依然是悲观锁,这就意味着
线程开始执行第一步就要获取锁,一旦获得锁,其他的线程进入后就会阻塞并等待锁。
`synchronized`
是悲观锁,尽管随着 JDK 版本的升级,synchronized 关键字已经“轻量级”了很多
(
[
前面有细讲,戳链接回顾
](
https://javabetter.cn/thread/synchronized.html
)
),但依然是悲观锁,
线程开始执行第一步就要获取锁,一旦获得锁,其他的线程进入后就会阻塞并等待锁。
如果不好理解,我们来举个生活中的例子:一个人进入厕所后首先把门锁上(获取锁),然后开始上厕所,这个时候有其他人来了就只能在外面等(阻塞),就算再急也没用。上完厕所完事后把门打开(解锁),其他人就可以进入了。
...
...
@@ -34,13 +34,13 @@ CAS(Compare-and-Swap)是一种被广泛应用在并发控制中的算法,
## 乐观锁与悲观锁
锁可以从不同的角度来分类。比如我们在前面讲
[
synchronized 到底锁的是什么
](
https://javabetter.cn/thread/synchronized.html
)
的时候,提到过偏向锁、轻量级锁、重量级锁,对吧?乐观锁和悲观锁也是一种分类方式。
锁可以从不同的角度来分类。比如我们在前面讲
[
synchronized 四种锁状态
](
https://javabetter.cn/thread/synchronized.html
)
的时候,提到过偏向锁、轻量级锁、重量级锁,对吧?乐观锁和悲观锁也是一种分类方式。
**悲观锁:**
### 悲观锁
对于悲观锁来说,它总是认为每次访问共享资源时会发生冲突,所以必须对每次数据操作加上锁,以保证临界区的程序同一时间只能有一个线程在执行。
**乐观锁:**
### 乐观锁
乐观锁,顾名思义,它是乐观派。乐观锁总是假设对共享资源的访问没有冲突,线程可以不停地执行,无需加锁也无需等待。一旦多个线程发生冲突,乐观锁通常使用一种称为 CAS 的技术来保证线程执行的安全性。
...
...
@@ -51,7 +51,7 @@ CAS(Compare-and-Swap)是一种被广泛应用在并发控制中的算法,
## 什么是 CAS
CAS 的全称是:比较并交换(Compare And Swap)。
在 CAS 中,有这样三个值:
在 CAS 中,有这样三个值:
-
V:要更新的变量(var)
-
E:预期值(expected)
...
...
@@ -78,11 +78,11 @@ CAS 的全称是:比较并交换(Compare And Swap)。在 CAS 中,有这
**当多个线程同时使用 CAS 操作一个变量时,只有一个会胜出,并成功更新,其余均会失败,但失败的线程并不会被挂起,仅是被告知失败,并且允许再次尝试,当然也允许失败的线程放弃操作。**
##
Java 实现
CAS 的原理
## CAS 的原理
前面提到,CAS 是一种原子操作。那么 Java 是怎样来使用 CAS 的呢?我们知道,在 Java 中,如果一个
[
方法是 native 的
](
https://javabetter.cn/oo/native-method.html
)
,那 Java 就不负责具体实现它,而是交给底层的 JVM 使用 C 语言 或者 C++ 去实现。
在 Java 中,有一个
`Unsafe`
类,它在
`sun.misc`
包中。它里面都是一些
`native`
方法,其中就有几个是关于 CAS 的:
在 Java 中,有一个
`Unsafe`
类
(
[
后面会细讲,戳链接直达
](
https://javabetter.cn/thread/Unsafe.html
)
)
,它在
`sun.misc`
包中。它里面都是一些
`native`
方法,其中就有几个是关于 CAS 的:
```
java
boolean
compareAndSwapObject
(
Object
o
,
long
offset
,
Object
expected
,
Object
x
);
...
...
@@ -94,9 +94,11 @@ Unsafe 对 CAS 的实现是通过 C++ 实现的,它的具体实现和操作系
Linux 的 X86 下主要是通过
`cmpxchgl`
这个指令在 CPU 上完成 CAS 操作的,但在多处理器情况下,必须使用
`lock`
指令加锁来完成。当然,不同的操作系统和处理器在实现方式上肯定会有所不同。
除了上面提到的方法,Unsafe 里面还有其它的方法。比如支持线程挂起和恢复的
`park`
和
`unpark`
方法,
[
LockSupport 类
](
https://javabetter.cn/thread/LockSupport.html
)
底层就调用了这两个方法。还有支持
[
反射
](
https://javabetter.cn/basic-extra-meal/fanshe.html
)
操作的
`allocateInstance()`
方法。
>CMPXCHG是“Compare and Exchange”的缩写,它是一种原子指令,用于在多核/多线程环境中安全地修改共享数据。CMPXCHG在很多现代微处理器体系结构中都有,例如Intel x86/x64体系。对于32位操作数,这个指令通常写作CMPXCHG,而在64位操作数中,它被称为CMPXCHG8B或CMPXCHG16B。
除了上面提到的方法,Unsafe 里面还有其它的方法。比如支持线程挂起和恢复的
`park`
和
`unpark`
方法,
[
LockSupport 类(后面会讲)
](
https://javabetter.cn/thread/LockSupport.html
)
底层就调用了这两个方法。还有支持
[
反射
](
https://javabetter.cn/basic-extra-meal/fanshe.html
)
操作的
`allocateInstance()`
方法。
##
具体如何实现的呢
?
##
CAS 如何实现原子操作
?
上面介绍了 Unsafe 类的几个支持 CAS 的方法。那 Java 具体是如何通过这几个方法来实现原子操作的呢?
...
...
@@ -104,16 +106,16 @@ JDK 提供了一些用于原子操作的类,在`java.util.concurrent.atomic`
![](
https://cdn.tobebetterjavaer.com/stutymore/cas-20230731195315.png
)
从名字就可以看出来这些类大概的用途:
从名字就可以看出来这些类大概的用途
(
[
原子类后面会细讲,戳链接直达
](
https://javabetter.cn/thread/atomic.html
)
)
:
-
原子更新基本类型
-
原子更新数组
-
原子更新引用
-
原子更新字段(属性)
这里我们以
`AtomicInteger`
类的
`getAndAdd(int delta)`
方法为例,来看看 Java 是如何实现原子操作的
,后面我们还会详细地讲其他的
[
原子类
](
https://javabetter.cn/thread/atomic.html
)
。
这里我们以
`AtomicInteger`
类的
`getAndAdd(int delta)`
方法为例,来看看 Java 是如何实现原子操作的。
先来看
看
getAndAdd 方法的源码:
先来看 getAndAdd 方法的源码:
```
java
public
final
int
getAndAdd
(
int
delta
)
{
...
...
@@ -185,7 +187,7 @@ public final int getAndAddInt(Object o, long offset, int delta) {
## CAS 的三大问题
尽管 CAS 提供了一种有效的同步手段,但也存在一些问题,主要有以下三个:
尽管 CAS 提供了一种有效的同步手段,但也存在一些问题,主要有以下三个:
ABA 问题、长时间自旋、多个共享变量的原子操作。
### ABA 问题
...
...
@@ -227,7 +229,7 @@ public boolean compareAndSet(V expectedReference,
-
如果上述检查通过,也就是说当前的引用和标记与预期的相同,那么接下来就会检查新的引用和标记是否也与当前的相同。如果相同,那么实际上没有必要做任何改变,这个方法就会返回 true。
-
如果新的引用或者标记与当前的不同,那么就会调用 casPair 方法来尝试更新 pair 对象。casPair 方法会尝试用 newReference 和 newStamp 创建的新的 Pair 对象替换当前的 pair 对象。如果替换成功,casPair 方法会返回 true;如果替换失败(也就是说在尝试替换的过程中,pair 对象已经被其他线程改变了),casPair 方法会返回 false。
###
循环时间长、开销大
###
长时间自旋
CAS 多与自旋结合。如果自旋 CAS 长时间不成功,会占用大量的 CPU 资源。
...
...
@@ -235,7 +237,7 @@ CAS 多与自旋结合。如果自旋 CAS 长时间不成功,会占用大量
pause 指令能让自旋失败时 cpu 睡眠一小段时间再继续自旋,从而使得读操作的频率降低很多,为解决内存顺序冲突而导致的 CPU 流水线重排的代价也会小很多。
###
只能保证一
个共享变量的原子操作
###
多
个共享变量的原子操作
当对一个共享变量执行操作时,CAS 能够保证该变量的原子性。但是对于多个共享变量,CAS 就无法保证操作的原子性,这时通常有两种做法:
...
...
docs/thread/pianxiangsuo.md
浏览文件 @
4dbf9259
此差异已折叠。
点击以展开。
docs/thread/synchronized.md
浏览文件 @
4dbf9259
---
title
:
synchronized到底锁的什么?偏向锁、轻量级锁、重量级锁到底是什么?
shortTitle
:
进击的synchronized
shortTitle
:
synchronized的四种锁状态
description
:
Java中的每一个对象都可以作为一个锁,这是synchronized实现同步的基础。当我们调用一个用synchronized关键字修饰的方法时,我们需要获取这个方法所在对象的锁。只有获取了这个锁,才可以执行这个方法。如果锁已经被其他线程获取,那么就会进入阻塞状态,直到锁被释放。
category
:
-
Java核心
...
...
@@ -12,7 +12,7 @@ head:
content
:
Java,并发编程,多线程,Thread,synchronized,偏向锁,轻量级锁,重量级锁,锁
---
# 第十节:
进击的synchronized
# 第十节:
synchronized的四种锁状态
前面一节我们讲了
[
synchronized 关键字的基本使用
](
https://javabetter.cn/thread/synchronized-1.html
)
,它能用来同步方法和代码块,那 synchronized 到底锁的是什么呢?随着 JDK 版本的升级,synchronized 又做出了哪些改变呢?“synchronized 性能很差”的谣言真的存在吗?
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录