Skip to content

Commit f77dfc5

Browse files
committed
lock
1 parent 53cd4ce commit f77dfc5

File tree

11 files changed

+370
-350
lines changed

11 files changed

+370
-350
lines changed

deploy.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ npm run docs:build
1010
cd docs/.vuepress/dist
1111

1212
# 如果是发布到自定义域名
13-
#echo 'www.lazyegg.net' > CNAME
13+
echo 'www.lazyegg.net' > CNAME
1414

1515
git init
1616
git add -A

docs/.vuepress/config.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,16 @@ function genJavaSidebar() {
8888
title: "JVM",
8989
collapsable: false,
9090
sidebarDepth: 2, // 可选的, 默认值是 1
91-
children: ["JVM/Runtime-Data-Areas", "JVM/OOM"]
91+
children: ["JVM/Runtime-Data-Areas","JVM/Java-Object","JVM/OOM","JVM/Reference"]
9292
},
9393
{
9494
title: "JUC",
9595
collapsable: false,
9696
children: [
9797
"JUC/Java-Memory-Model",
9898
"JUC/volatile","JUC/synchronized","JUC/CAS",
99-
"JUC/CountDownLatch、CyclicBarrier、Semaphore"
99+
"JUC/CountDownLatch、CyclicBarrier、Semaphore",
100+
"JUC/Concurrent-Container"
100101
]
101102
}
102103
];

docs/.vuepress/dist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Subproject commit 008a48f7972aba21b62f8886e09a4041e5c79eee
1+
Subproject commit 3282ebf97e1a3aa98cd92ed7c79ecd5ba132453d
15 KB
Loading
57.9 KB
Loading

docs/big-data/Bloom-Filter.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
>文章收录在 GitHub [JavaKeeper](https://github.com/Jstarfish/JavaKeeper) ,N线互联网开发必备技能兵器谱
2-
31
## 什么是 BloomFilter
42

53
**布隆过滤器**(英语:Bloom Filter)是 1970 年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。主要用于判断一个元素是否在一个集合中。
@@ -381,7 +379,11 @@ public class RedissonBloomFilterDemo {
381379

382380
由于使用较少,暂不深入。
383381

384-
![](https://tva1.sinaimg.cn/large/007S8ZIlly1gdu79z432kj30ku0aumy2.jpg)
382+
383+
384+
> 文章持续更新,可以微信搜「 **JavaKeeper** 」第一时间阅读,无套路领取 500+ 本电子书和 30+ 视频教学和源码,本文 **GitHub** [github.com/JavaKeeper](https://github.com/Jstarfish/JavaKeeper) 已经收录,Javaer 开发、面试必备技能兵器谱,有你想要的。
385+
386+
385387

386388
## 参考与感谢
387389

docs/data-store/Redis/Redis-BloomFilter.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
## 隆过滤器是什么
1+
## 布隆过滤器是什么
22

33
布隆过滤器可以理解为一个不怎么精确的 set 结构,当你使用它的 contains 方法判断某个对象是否存在时,它可能会误判。但是布隆过滤器也不是特别不精确,只要参数设置的合理,它的精确度可以控制的相对足够精确,只会有小小的误判概率。
44

docs/data-structure-algorithms/Dynamic-Programming.md

Lines changed: 327 additions & 288 deletions
Large diffs are not rendered by default.
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
>
1+
# 并发容器
2+
3+
TODO

docs/java/JUC/synchronized.md

Lines changed: 27 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -4,67 +4,45 @@ https://www.cnblogs.com/aspirant/p/11470858.html
44

55
## 一、前言
66

7+
记得开始学习 Java 的时候,一遇到多线程情况就使用 synchronized,相对于当时的我们来说 synchronized 是这么的神奇而又强大,那个时候我们赋予它一个名字“同步”,也成为了我们解决多线程情况的百试不爽的良药。但是,随着学习的进行我们知道在 JDK1.5 之前 synchronized 是一个重量级锁,相对于 j.u.c.Lock,它会显得那么笨重,以至于我们认为它不是那么的高效而慢慢摒弃它。
78

9+
不过,随着 Javs SE 1.6 对 synchronized 进行的各种优化后,synchronized 并不会显得那么重了。下面来一起探索 synchronized 的基本使用、实现机制、Java是如何对它进行了优化、锁优化机制、锁的存储结构等升级过程。
810

911

1012

11-
## 二、使用
12-
13-
每个初学多线程的 Javaer,在遇到这种多线程问题的时候,肯定会先想到 Synchronized,我们把它称为“同步”,
13+
## 二、作用
1414

1515
Synchronized 是 Java 中解决并发问题的一种最常用的方法,也是最简单的一种方法。Synchronized 的作用主要有三个:
1616

1717
1. 原子性:确保线程互斥的访问同步代码;
18-
1918
2. 可见性:保证共享变量的修改能够及时可见,其实是通过 Java 内存模型中的 “**对一个变量unlock操作之前,必须要同步到主内存中;如果对一个变量进行lock操作,则将会清空工作内存中此变量的值,在执行引擎使用此变量前,需要重新从主内存中load操作或assign操作初始化变量值**” 来保证的;
19+
3. 有序性:有效解决重排序问题,即 “一个 unlock 操作先行发生(happen-before)于后面对同一个锁的 lock 操作”;
2020

21-
3. 有序性:有效解决重排序问题,即 “一个unlock操作先行发生(happen-before)于后面对同一个锁的lock操作”;
22-
23-
### 2.1 synchronized 的用法分类
24-
25-
synchronized 的用法可以从两个维度上面分类:
26-
27-
#### 根据修饰对象分类
2821

29-
synchronized 可以修饰方法和代码块
3022

31-
- 修饰代码块
32-
- synchronized(this|object) {}
33-
- synchronized(类.class) {}
34-
- 修饰方法
35-
- 修饰非静态方法
36-
- 修饰静态方法
23+
## 三、使用
3724

38-
#### 根据获取的锁分类
39-
40-
- 获取对象锁
41-
- synchronized(this|object) {}
42-
- 修饰非静态方法
43-
- 获取类锁
44-
- synchronized(类.class) {}
45-
- 修饰静态方法
25+
在 Java 代码中使用 synchronized 可以使用在代码块和方法中,根据 synchronized 用的位置可以有这些使用场景:
4626

4727
![img](https://user-gold-cdn.xitu.io/2018/4/30/16315cc79aaac173?imageslim)
4828

49-
如图,synchronized可以用在**方法**上也可以使用在**代码块**中,其中方法是实例方法和静态方法分别锁的是该类的实例对象和该类的对象。而使用在代码块中也可以分为三种,具体的可以看上面的表格。这里的需要注意的是:**如果锁的是类对象的话,尽管new多个实例对象,但他们仍然是属于同一个类依然会被锁住,即线程之间保证同步关系**
29+
如图,synchronized 可以用在**方法**上也可以使用在**代码块**中,其中方法是实例方法和静态方法分别锁的是该类的实例对象和该类的对象。而使用在代码块中也可以分为三种,具体的可以看上面的表格。这里需要注意的是:**如果锁的是类对象的话,尽管 new 多个实例对象,但他们仍然是属于同一个类依然会被锁住,即线程之间保证同步关系**
30+
5031

5132

33+
## 四、原理
5234

53-
从语法上讲,Synchronized 可以把任何一个非null对象作为"锁",在 HotSpot JVM 实现中,**锁有个专门的名字:对象监视器(Object Monitor)**
35+
从语法上讲,synchronized 可以把任何一个非 null 对象作为"锁",在 HotSpot JVM 实现中,**锁有个专门的名字:对象监视器(Object Monitor)**
5436

55-
Synchronized 概括来说其实总共有三种用法:
37+
synchronized 概括来说其实总共有三种用法:
5638

5739
1. 当 synchronized 作用在实例方法时,监视器锁(monitor)便是对象实例(this);
5840
2. 当 synchronized 作用在静态方法时,监视器锁(monitor)便是对象的 Class 实例,因为 Class 数据存在于永久代,因此静态方法锁相当于该类的一个全局锁;
59-
3. 当 synchronized 作用在某一个对象实例时,监视器锁(monitor)便是括号括起来的对象实例;
41+
3. 当 synchronized 作用在某一个对象实例时(即代码块的形式),监视器锁(monitor)便是括号括起来的对象实例;
42+
6043

61-
| 作用范围 | 锁对象 |
62-
| :--------- | :----------------------------------------------------------- |
63-
| 非静态方法 | 当前对象 => this |
64-
| 静态方法 | 类对象 => SynchronizedSample.class (一切皆对象,这个是类对象) |
65-
| 代码块 | 指定对象 => lock |
6644

67-
注意,synchronized 内置锁是一种对象锁(锁的是对象而非引用变量),**作用粒度是对象 ,可以用来实现对 临界资源的同步互斥访问 ,是可重入的。其可重入最大的作用是避免死锁**,如:
45+
注意,synchronized 内置锁是一种对象锁(锁的是对象而非引用变量),**作用粒度是对象 ,可以用来实现对临界资源的同步互斥访问 ,是可重入的。其可重入最大的作用是避免死锁**,如:
6846

6947
子类同步方法调用了父类同步方法,如没有可重入的特性,则会发生死锁;
7048

@@ -97,27 +75,25 @@ public class SynchronizedDemo {
9775
}
9876
```
9977

100-
上面的代码中有一个同步代码块,锁住的是类对象,并且还有一个静态方法,锁住的依然是该类的类对象。编译之后,切换到 SynchronizedDemo.class 的同级目录之后,然后用**javap -v SynchronizedDemo.class**查看字节码文件:
78+
上面的代码中有一个同步代码块,锁住的是类对象,并且还有一个静态方法,锁住的依然是该类的类对象。编译之后,切换到 SynchronizedDemo.class 的同级目录之后,然后用 **javap -v SynchronizedDemo.class** 查看字节码文件:
10179

10280
![SynchronizedDemo.class](https://user-gold-cdn.xitu.io/2018/4/30/16315cce259af0d2?imageView2/0/w/1280/h/960/format/webp/ignore-error/1)
10381

104-
如图,上面用黄色高亮的部分就是需要注意的部分了,这也是添Synchronized关键字之后独有的。执行同步代码块后首先要先执行**monitorenter**指令,退出的时候**monitorexit**指令。通过分析之后可以看出,使用Synchronized进行同步,其关键就是必须要对对象的监视器monitor进行获取,当线程获取monitor后才能继续往下执行,否则就只能等待。而这个获取的过程是**互斥**的,即同一时刻只有一个线程能够获取到monitor。上面的demo中在执行完同步代码块之后紧接着再会去执行一个静态同步方法,而这个方法锁的对象依然就这个类对象,那么这个正在执行的线程还需要获取该锁吗?答案是不必的,从上图中就可以看出来,执行静态同步方法的时候就只有一条monitorexit指令,并没有monitorenter获取锁的指令。这就是**锁的重入性**,即在同一锁程中,线程不需要再次获取同一把锁。Synchronized先天具有重入性。**每个对象拥有一个计数器,当线程获取该对象锁后,计数器就会加一,释放锁后就会将计数器减一**
82+
如图,上面用黄色高亮的部分就是需要注意的部分了,这也是添 synchronized 关键字之后独有的。执行同步代码块后首先要先执行 **monitorenter** 指令,退出的时候 **monitorexit** 指令。通过分析之后可以看出,使用synchronized 进行同步,其关键就是必须要对对象的监视器 monitor 进行获取,当线程获取 monitor 后才能继续往下执行,否则就只能等待。而这个获取的过程是**互斥**的,即同一时刻只有一个线程能够获取到 monitor。上面的 demo 中在执行完同步代码块之后紧接着再会去执行一个静态同步方法,而这个方法锁的对象依然就这个类对象,那么这个正在执行的线程还需要获取该锁吗?答案是不必的,从上图中就可以看出来,执行静态同步方法的时候就只有一条 monitorexit 指令,并没有 monitorenter 获取锁的指令。这就是**锁的重入性**,即在同一锁程中,线程不需要再次获取同一把锁。synchronized 先天具有重入性。**每个对象拥有一个计数器,当线程获取该对象锁后,计数器就会加一,释放锁后就会将计数器减一**
10583

10684

10785

108-
synchronized关键字不能继承
86+
synchronized 关键字不能继承
10987

110-
对于父类中的 synchronized 修饰方法,子类在覆盖该方法时,默认情况下不是同步的,必须显示的使用 synchronized 关键字修饰才行。
88+
对于父类中的 synchronized 修饰方法,子类在覆盖该方法时,默认情况下不是同步的,必须显示的使用 synchronized 关键字修饰才行。
11189

112-
在定义接口方法时不能使用synchronized关键字
90+
在定义接口方法时不能使用 synchronized 关键字
11391

114-
构造方法不能使用synchronized关键字,但可以使用synchronized代码块来进行同步
92+
构造方法不能使用 synchronized 关键字,但可以使用 synchronized 代码块来进行同步
11593

11694

11795

118-
## 三、原理
119-
120-
数据同步需要依赖锁,那锁的同步又依赖谁?**synchronized给出的答案是在软件层面依赖JVM,而j.u.c.Lock给出的答案是在硬件层面依赖特殊的CPU指令。**
96+
数据同步需要依赖锁,那锁的同步又依赖谁?**synchronized给出的答案是在软件层面依赖 JVM,而 j.u.c.Lock给出的答案是在硬件层面依赖特殊的 CPU 指令。**
12197

12298
```java
12399
public class SynchronizedClassDemo {
@@ -178,7 +154,7 @@ TODO:为什么也会有两次退出???
178154
179155

180156

181-
通过上面两段描述,我们应该能很清楚的看出Synchronized的实现原理**Synchronized的语义底层是通过一个monitor的对象来完成,其实wait/notify等方法也依赖于monitor对象,这就是为什么只有在同步的块或者方法中才能调用wait/notify等方法,否则会抛出java.lang.IllegalMonitorStateException的异常的原因。**
157+
通过上面两段描述,我们应该能很清楚的看出 synchronized 的实现原理**synchronized 的语义底层是通过一个monitor的对象来完成,其实wait/notify等方法也依赖于monitor对象,这就是为什么只有在同步的块或者方法中才能调用wait/notify等方法,否则会抛出java.lang.IllegalMonitorStateException的异常的原因。**
182158

183159

184160

@@ -198,11 +174,11 @@ public class SynchronizedMethod {
198174

199175
反编译结果
200176

201-
从编译的结果来看,方法的同步并没有通过指令 `monitorenter``monitorexit` 来完成(理论上其实也可以通过这两条指令来实现),不过相对于普通方法,其常量池中多了 `ACC_SYNCHRONIZED` 标示符。JVM就是根据该标示符来实现方法的同步的
177+
从编译的结果来看,方法的同步并没有通过指令 `monitorenter``monitorexit` 来完成(理论上其实也可以通过这两条指令来实现),不过相对于普通方法,其常量池中多了 `ACC_SYNCHRONIZED` 标示符。JVM 就是根据该标示符来实现方法的同步的
202178

203179
> 当方法调用时,调用指令将会检查方法的 ACC_SYNCHRONIZED 访问标志是否被设置,如果设置了,执行线程将先获取monitor,获取成功之后才能执行方法体,方法执行完后再释放monitor。**在方法执行期间,其他任何线程都无法再获得同一个monitor对象。**
204180
205-
两种同步方式本质上没有区别,只是方法的同步是一种隐式的方式来实现,无需通过字节码来完成。两个指令的执行是JVM通过调用操作系统的互斥原语mutex来实现,被阻塞的线程会被挂起、等待重新调度,会导致“用户态和内核态”两个态之间来回切换,对性能有较大影响。
181+
两种同步方式本质上没有区别,只是方法的同步是一种隐式的方式来实现,无需通过字节码来完成。两个指令的执行是 JVM 通过调用操作系统的互斥原语 mutex 来实现,被阻塞的线程会被挂起、等待重新调度,会导致“用户态和内核态”两个态之间来回切换,对性能有较大影响。
206182

207183

208184

@@ -765,4 +741,6 @@ ObjectMonitor中有两个队列,_WaitSet 和 _EntryList,用来保存ObjectWa
765741

766742
## 参考
767743

768-
https://juejin.im/post/5ae6dc04f265da0ba351d3ff
744+
https://juejin.im/post/5ae6dc04f265da0ba351d3ff
745+
746+
https://blog.csdn.net/zhengwangzw/article/details/105141484

0 commit comments

Comments
 (0)