Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
沉默王二
Jmx Java
提交
da218463
J
Jmx Java
项目概览
沉默王二
/
Jmx Java
8 个月 前同步成功
通知
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,体验更适合开发者的 AI 搜索 >>
提交
da218463
编写于
8月 31, 2023
作者:
沉默王二
💬
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
读写锁
上级
4dbf9259
变更
4
展开全部
隐藏空白更改
内联
并排
Showing
4 changed file
with
185 addition
and
105 deletion
+185
-105
README.md
README.md
+1
-1
docs/home.md
docs/home.md
+1
-1
docs/thread/lock.md
docs/thread/lock.md
+111
-58
docs/thread/reentrantLock.md
docs/thread/reentrantLock.md
+72
-45
未找到文件。
README.md
浏览文件 @
da218463
...
...
@@ -257,7 +257,7 @@
-
[
深入浅出偏向锁
](
docs/thread/pianxiangsuo.md
)
-
[
CAS详解
](
docs/thread/cas.md
)
-
[
AQS详解
](
docs/thread/aqs.md
)
-
[
锁分类
及 JUC 包下的那些锁
](
docs/thread/lock.md
)
-
[
锁分类
和 JUC
](
docs/thread/lock.md
)
-
[
重入锁ReentrantLock
](
docs/thread/reentrantLock.md
)
-
[
读写锁ReentrantReadWriteLock
](
docs/thread/ReentrantReadWriteLock.md
)
-
[
协作类Condition
](
docs/thread/condition.md
)
...
...
docs/home.md
浏览文件 @
da218463
...
...
@@ -266,7 +266,7 @@ head:
-
[
深入浅出偏向锁
](
thread/pianxiangsuo.md
)
-
[
CAS详解
](
thread/cas.md
)
-
[
AQS详解
](
thread/aqs.md
)
-
[
锁分类
及 JUC 包下的那些锁
](
thread/lock.md
)
-
[
锁分类
和 JUC
](
thread/lock.md
)
-
[
重入锁ReentrantLock
](
thread/reentrantLock.md
)
-
[
读写锁ReentrantReadWriteLock
](
thread/ReentrantReadWriteLock.md
)
-
[
协作类Condition
](
thread/condition.md
)
...
...
docs/thread/lock.md
浏览文件 @
da218463
此差异已折叠。
点击以展开。
docs/thread/reentrantLock.md
浏览文件 @
da218463
...
...
@@ -119,7 +119,7 @@ protected final boolean tryAcquire(int acquires) {
## ReentrantLock 的使用
ReentrantLock 的使用方式与
synchronized
关键字类似,都是通过加锁和释放锁来实现同步的。我们来看看 ReentrantLock 的使用方式,以非公平锁为例:
ReentrantLock 的使用方式与
[
synchronized
](
https://javabetter.cn/thread/synchronized-1.html
)
关键字类似,都是通过加锁和释放锁来实现同步的。我们来看看 ReentrantLock 的使用方式,以非公平锁为例:
```
java
public
class
ReentrantLockTest
{
...
...
@@ -181,70 +181,97 @@ private static final ReentrantLock lock = new ReentrantLock(true);
需要注意的是,使用 ReentrantLock 时,必须在 finally 块中手动释放锁。
##
Condition 接口
##
ReentrantLock 与 synchronized
[
Condition 接口
](
https://javabetter.cn/thread/condition.html
)
是与 Lock 绑定的,可以理解为一个 Lock 对象可以绑定多个 Condition 对象,Condition 接口提供了类似于 Object 的 wait、notify、notifyAll 等方法,与 Lock 一起使用可以实现等待/通知模式,比如实现一个阻塞队列:
ReentrantLock 与 synchronized 关键字都是用来实现同步的,那么它们之间有什么区别呢?我们来看看它们的对比:
-
**ReentrantLock 是一个类,而 synchronized 是 Java 中的关键字**
;
-
**ReentrantLock 可以实现选择性通知(可以绑定多个 [Condition](https://javabetter.cn/thread/condition.html)(后面会细讲,戳链接直达)),而 synchronized 只能唤醒一个线程或者唤醒全部线程**
;
-
**ReentrantLock 是可重入锁,而 synchronized 不是**
;
-
ReentrantLock 必须手动释放锁。通常需要在 finally 块中调用 unlock 方法以确保锁被正确释放。synchronized 会自动释放锁,当同步块执行完毕时,由 JVM 自动释放,不需要手动操作。
-
ReentrantLock: 通常提供更好的性能,特别是在高竞争环境下。synchronized: 在某些情况下,性能可能稍差一些,但随着 JDK 版本的升级,性能差距已经不大了。
以下是一个简单的性能比较demo:
```
java
public
class
BlockingQueue
<
T
>
{
private
final
Lock
lock
=
new
ReentrantLock
();
private
final
Condition
notFull
=
lock
.
newCondition
();
private
final
Condition
notEmpty
=
lock
.
newCondition
();
private
final
Object
[]
items
=
new
Object
[
100
];
private
int
putptr
,
takeptr
,
count
;
public
void
put
(
T
t
)
throws
InterruptedException
{
import
java.util.concurrent.locks.ReentrantLock
;
public
class
PerformanceTest
{
private
static
final
int
NUM_THREADS
=
10
;
private
static
final
int
NUM_INCREMENTS
=
1_000_000
;
private
int
count1
=
0
;
private
int
count2
=
0
;
private
final
ReentrantLock
lock
=
new
ReentrantLock
();
private
final
Object
syncLock
=
new
Object
();
public
void
increment1
()
{
lock
.
lock
();
try
{
while
(
count
==
items
.
length
)
{
notFull
.
await
();
}
items
[
putptr
]
=
t
;
if
(++
putptr
==
items
.
length
)
{
putptr
=
0
;
}
++
count
;
notEmpty
.
signal
();
count1
++;
}
finally
{
lock
.
unlock
();
}
}
public
T
take
()
throws
InterruptedException
{
lock
.
lock
();
try
{
while
(
count
==
0
)
{
notEmpty
.
await
();
}
Object
x
=
items
[
takeptr
];
if
(++
takeptr
==
items
.
length
)
{
takeptr
=
0
;
}
--
count
;
notFull
.
signal
();
return
(
T
)
x
;
}
finally
{
lock
.
unlock
();
public
void
increment2
()
{
synchronized
(
syncLock
)
{
count2
++;
}
}
public
static
void
main
(
String
[]
args
)
throws
InterruptedException
{
PerformanceTest
test
=
new
PerformanceTest
();
// Test ReentrantLock
long
startTime
=
System
.
nanoTime
();
Thread
[]
threads
=
new
Thread
[
NUM_THREADS
];
for
(
int
i
=
0
;
i
<
NUM_THREADS
;
i
++)
{
threads
[
i
]
=
new
Thread
(()
->
{
for
(
int
j
=
0
;
j
<
NUM_INCREMENTS
;
j
++)
{
test
.
increment1
();
}
});
threads
[
i
].
start
();
}
for
(
Thread
thread
:
threads
)
{
thread
.
join
();
}
long
endTime
=
System
.
nanoTime
();
System
.
out
.
println
(
"ReentrantLock time: "
+
(
endTime
-
startTime
)
+
" ns"
);
// Test synchronized
startTime
=
System
.
nanoTime
();
for
(
int
i
=
0
;
i
<
NUM_THREADS
;
i
++)
{
threads
[
i
]
=
new
Thread
(()
->
{
for
(
int
j
=
0
;
j
<
NUM_INCREMENTS
;
j
++)
{
test
.
increment2
();
}
});
threads
[
i
].
start
();
}
for
(
Thread
thread
:
threads
)
{
thread
.
join
();
}
endTime
=
System
.
nanoTime
();
System
.
out
.
println
(
"synchronized time: "
+
(
endTime
-
startTime
)
+
" ns"
);
}
}
```
代码很简单,就是一个阻塞队列的实现,put 方法用来向队列中添加元素,take 方法用来从队列中获取元素。我们来看看 put 方法的实现,首先获取锁,然后判断队列是否已满,如果已满则调用
`notFull.await()`
方法阻塞当前线程,直到队列不满,然后将元素添加到队列中,最后调用
`notEmpty.signal()`
方法唤醒一个等待的线程。take 方法的实现与 put 方法类似,不再赘述。
来看输出结果:
## 与 synchronized 关键字的比较
ReentrantLock 与 synchronized 关键字都是用来实现同步的,那么它们之间有什么区别呢?我们来看看它们的对比:
```
ReentrantLock time: 269913857 ns
synchronized time: 350595013 ns
```
-
**ReentrantLock 是一个类,而 synchronized 是 Java 中的关键字,synchronized 是内置的语言实现**
;
-
**ReentrantLock 可以实现选择性通知(锁可以绑定多个 Condition),而 synchronized 只能唤醒一个线程或者唤醒全部线程**
;
-
**ReentrantLock 是可重入锁,而 synchronized 不是**
;
-
ReentrantLock 必须手动释放锁。通常需要在 finally 块中调用 unlock 方法以确保锁被正确释放。synchronized: 自动释放锁。当同步块执行完毕时,JVM 会自动释放锁,不需要手动操作。
-
ReentrantLock: 通常提供更好的性能,特别是在高竞争环境下。ynchronized: 在某些情况下,性能可能稍差一些,但在现代 JVM 实现中,性能差距通常不大。
这个测试在两种锁机制下尝试执行多次增量操作,然后测量所需的时间。
## 小结
本篇主要介绍了 ReentrantLock 的实现原理,以及与 synchronized 关键字的比较。
ReentrantLock 是一个类,而 synchronized 是 Java 中的关键字,synchronized 是内置的语言实现。ReentrantLock 可以实现选择性通知(锁可以绑定多个 Condition),而 synchronized 只能唤醒一个线程或者唤醒全部线程。ReentrantLock 是可重入锁,而 synchronized 不是。ReentrantLock 必须手动释放锁。通常需要在 finally 块中调用 unlock 方法以确保锁被正确释放。synchronized: 自动释放锁。当同步块执行完毕时,JVM 会自动释放锁,不需要手动操作。ReentrantLock: 通常提供更好的性能,特别是在高竞争环境下。ynchronized: 在某些情况下,性能可能稍差一些,但在现代 JVM 实现中,性能差距通常不大。
本篇主要介绍了 ReentrantLock 的实现原理,以及与 synchronized 关键字的比较。
>编辑:沉默王二,编辑前的内容主要来自于CL0610的 GitHub 仓库[https://github.com/CL0610/Java-concurrency](https://github.com/CL0610/Java-concurrency/blob/master/10.彻底理解ReentrantLock/彻底理解ReentrantLock.md)
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录