Skip to content

Commit 4b12e45

Browse files
committed
java
1 parent da485ec commit 4b12e45

14 files changed

Lines changed: 2819 additions & 0 deletions
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
2+
3+
4+
5+
6+
7+
8+
9+
10+
11+
12+
13+
14+
15+
16+
17+
18+
19+
20+
21+
22+
23+
24+
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
#### 目录介绍
2+
- 01.继承Thread类的方式卖电影票案例
3+
- 02.实现Runnable接口的方式卖电影票
4+
- 03.买电影票出现了同票和负数票的原因分析
5+
- 04.线程安全问题的产生原因分析
6+
- 05.同步代码块的方式解决线程安全问题
7+
8+
9+
10+
11+
12+
### 好消息
13+
- 博客笔记大汇总【16年3月到至今】,包括Java基础及深入知识点,Android技术博客,Python学习笔记等等,还包括平时开发中遇到的bug汇总,当然也在工作之余收集了大量的面试题,长期更新维护并且修正,持续完善……开源的文件是markdown格式的!同时也开源了生活博客,从12年起,积累共计N篇[近100万字,陆续搬到网上],转载请注明出处,谢谢!
14+
- **链接地址:https://github.com/yangchong211/YCBlogs**
15+
- 如果觉得好,可以star一下,谢谢!当然也欢迎提出建议,万事起于忽微,量变引起质变!
16+
17+
18+
19+
20+
21+
### 01.继承Thread类的方式卖电影票案例
22+
- 代码如下所示
23+
```
24+
public class ThreadDemo {
25+
public static void main(String[] args) {
26+
/**
27+
* 需求:某电影院目前正在上映贺岁大片,共有100张票,而它有3个售票窗口售票,请设计一个程序模拟该电影院售票。
28+
*/
29+
// 创建3个线程对象
30+
SellTicktes t1 = new SellTicktes() ;
31+
SellTicktes t2 = new SellTicktes() ;
32+
SellTicktes t3 = new SellTicktes() ;
33+
// 设置名称
34+
t1.setName("窗口1") ;
35+
t2.setName("窗口2") ;
36+
t3.setName("窗口3") ;
37+
// 启动线程
38+
t1.start() ;
39+
t2.start() ;
40+
t3.start() ;
41+
}
42+
}
43+
44+
public class SellTicktes extends Thread {
45+
private static int num = 100 ;
46+
@Override
47+
public void run() {
48+
/**
49+
* 定义总票数
50+
*
51+
* 如果我们把票数定义成了局部变量,那么表示的意思是每一个窗口出售了各自的100张票; 而我们的需求是: 总共有100张票
52+
* 而这100张票要被3个窗口出售; 因此我们就不能把票数定义成局部变量,只能定义成成员变量
53+
*/
54+
// 模拟售票
55+
while(true) {
56+
if( num > 0 ) {
57+
System.out.println(Thread.currentThread().getName() + "正在出售" + (num--) + "张票");
58+
}
59+
}
60+
}
61+
}
62+
```
63+
64+
65+
66+
### 02.实现Runnable接口的方式卖电影票
67+
- 代码如下所示,假设有三个窗口
68+
```
69+
public class SellTicektesDemo {
70+
public static void main(String[] args) {
71+
// 创建SellTicektes对象
72+
SellTicektes st = new SellTicektes() ;
73+
// 创建Thread对象
74+
Thread t1 = new Thread(st , "窗口1") ;
75+
Thread t2 = new Thread(st , "窗口2") ;
76+
Thread t3 = new Thread(st , "窗口3") ;
77+
// 启动线程
78+
t1.start() ;
79+
t2.start() ;
80+
t3.start() ;
81+
}
82+
}
83+
84+
public class SellTicektes implements Runnable {
85+
private static int num = 100 ;
86+
@Override
87+
public void run() {
88+
while(true) {
89+
if(num > 0) {
90+
System.out.println(Thread.currentThread().getName() + "正在出售第" + (num--) + "张票");
91+
}
92+
}
93+
}
94+
}
95+
```
96+
97+
### 03.买电影票出现了同票和负数票的原因分析
98+
- 讲解过电影院售票程序,从表面上看不出什么问题,但是在真实生活中,售票时网络是不能实时传输的,总是存在延迟的情况,所以,在出售一张票以后,需要一点时间的延迟。改实现接口方式的卖票程序,每次卖票延迟100毫秒
99+
```
100+
public class ThreadDemo {
101+
public static void main(String[] args) {
102+
// 创建3个线程对象
103+
SellTicktes t1 = new SellTicktes() ;
104+
SellTicktes t2 = new SellTicktes() ;
105+
SellTicktes t3 = new SellTicktes() ;
106+
// 设置名称
107+
t1.setName("窗口1") ;
108+
t2.setName("窗口2") ;
109+
t3.setName("窗口3") ;
110+
// 启动线程
111+
t1.start() ;
112+
t2.start() ;
113+
t3.start() ;
114+
}
115+
}
116+
117+
public class SellTicktes extends Thread {
118+
private static int num = 100 ;
119+
@Override
120+
public void run() {
121+
// 模拟售票
122+
while(true) {
123+
if( num > 0 ) {
124+
try {
125+
Thread.sleep(100) ;
126+
} catch (InterruptedException e) {
127+
e.printStackTrace();
128+
}
129+
System.out.println(Thread.currentThread().getName() + "正在出售" + (num--) + "张票");
130+
}
131+
}
132+
}
133+
}
134+
```
135+
136+
137+
### 04.线程安全问题的产生原因分析
138+
- 1.4.1 首先想为什么出现问题?
139+
- 是否是多线程环境,是否有共享数据,是否有多条语句操作共享数据
140+
- 1.4.2 如何解决多线程安全问题呢?
141+
- 基本思想:让程序没有安全问题的环境。怎么实现呢?把多个语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行即可。
142+
143+
144+
145+
146+
### 05.同步代码块的方式解决线程安全问题
147+
- **1.5.1 同步代码块的格式**
148+
- 同步可以解决安全问题的根本原因就在那个对象上。该对象如同锁的功能
149+
```
150+
synchronized(对象){
151+
需要同步的代码;
152+
}
153+
```
154+
155+
- **1.5.2 同步代码块优势和劣势**
156+
- 同步的好处:同步的出现解决了多线程的安全问题。
157+
- 同步的弊端:当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。
158+
159+
160+
161+
162+
163+
164+
### 其他介绍
165+
#### 01.关于博客汇总链接
166+
- 1.[技术博客汇总](https://www.jianshu.com/p/614cb839182c)
167+
- 2.[开源项目汇总](https://blog.csdn.net/m0_37700275/article/details/80863574)
168+
- 3.[生活博客汇总](https://blog.csdn.net/m0_37700275/article/details/79832978)
169+
- 4.[喜马拉雅音频汇总](https://www.jianshu.com/p/f665de16d1eb)
170+
- 5.[其他汇总](https://www.jianshu.com/p/53017c3fc75d)
171+
172+
173+
174+
#### 02.关于我的博客
175+
- github:https://github.com/yangchong211
176+
- 知乎:https://www.zhihu.com/people/yczbj/activities
177+
- 简书:http://www.jianshu.com/u/b7b2c6ed9284
178+
- csdn:http://my.csdn.net/m0_37700275
179+
- 喜马拉雅听书:http://www.ximalaya.com/zhubo/71989305/
180+
- 开源中国:https://my.oschina.net/zbj1618/blog
181+
- 泡在网上的日子:http://www.jcodecraeer.com/member/content_list.php?channelid=1
182+
183+
- 阿里云博客:https://yq.aliyun.com/users/article?spm=5176.100- 239.headeruserinfo.3.dT4bcV
184+
- segmentfault头条:https://segmentfault.com/u/xiangjianyu/articles
185+
- 掘金:https://juejin.im/user/5939433efe88c2006afa0c6e
186+
187+
188+
189+
190+
191+
192+
193+
194+
195+
196+
197+
198+
199+
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
#### 目录介绍
2+
- 01.线程安全特性
3+
- 1.1 什么是线程安全
4+
- 1.2 线程安全级别
5+
- 1.3 线程安全必备
6+
- 02.多线程三要素
7+
- 2.1 三要素分别是啥
8+
- 2.2 如何理解原子性
9+
- 2.3 如何理解可见性
10+
- 2.4 如何理解有序性
11+
- 2.5 三要素作用
12+
- 03.处理多线程并发
13+
- 3.1 保证原子性
14+
- 3.2 保证可见性
15+
- 3.3 保证有序性
16+
- 3.4 回答一个问题
17+
18+
19+
20+
21+
### 好消息
22+
- 博客笔记大汇总【16年3月到至今】,包括Java基础及深入知识点,Android技术博客,Python学习笔记等等,还包括平时开发中遇到的bug汇总,当然也在工作之余收集了大量的面试题,长期更新维护并且修正,持续完善……开源的文件是markdown格式的!同时也开源了生活博客,从12年起,积累共计N篇[近100万字,陆续搬到网上],转载请注明出处,谢谢!
23+
- **链接地址:https://github.com/yangchong211/YCBlogs**
24+
- 如果觉得好,可以star一下,谢谢!当然也欢迎提出建议,万事起于忽微,量变引起质变!
25+
26+
27+
28+
### 00.并发切入点
29+
- 并发切入点是什么?
30+
- 并发分析的切入点分为**两个核心,三大性质**。两大核心:JMM内存模型(主内存和工作内存)以及happens-before;三条性质:原子性,可见性,有序性。
31+
32+
33+
34+
35+
### 01.线程安全特性
36+
#### 1.1 什么是线程安全
37+
- 什么是线程安全
38+
- 线程安全就是当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那这个对象是线程安全的。
39+
- 通俗来讲,如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的,或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题 。
40+
- 并发切入点是什么?
41+
- 并发分析的切入点分为**两个核心,三大性质**。两大核心:JMM内存模型(主内存和工作内存)以及happens-before;三条性质:原子性,可见性,有序性。
42+
43+
44+
45+
46+
47+
#### 1.2 线程安全级别
48+
- 线程安全也是有几个级别
49+
- 不可变:
50+
- 像String、Integer、Long这些,都是final类型的类,任何一个线程都改变不了它们的值,要改变除非新创建一个,因此这些不可变对象不需要任何同步手段就可以直接在多线程环境下使用
51+
- 绝对线程安全
52+
- 不管运行时环境如何,调用者都不需要额外的同步措施。要做到这一点通常需要付出许多额外的代价,Java中标注自己是线程安全的类,实际上绝大多数都不是线程安全的,不过绝对线程安全的类,Java中也有,比方说CopyOnWriteArrayList、CopyOnWriteArraySet
53+
- 相对线程安全
54+
- 相对线程安全也就是我们通常意义上所说的线程安全,像Vector这种,add、remove方法都是原子操作,不会被打断,但也仅限于此,如果有个线程在遍历某个Vector、有个线程同时在add这个Vector,99%的情况下都会出现ConcurrentModificationException,也就是fail-fast机制。
55+
- 线程非安全[技术博客大总结](https://github.com/yangchong211/YCBlogs)
56+
- ArrayList、LinkedList、HashMap等都是线程非安全的类.
57+
58+
59+
### 1.3 线程安全必备
60+
- 线程安全需要保证几个基本特性
61+
- 1、原子性,简单说就是相关操作不会中途被其他线程干扰,一般通过同步机制实现。
62+
- 2、可见性,是一个线程修改了某个共享变量,其状态能够立即被其他线程知晓,通常被解释为将线程本地状态反映到主内存上,volatile 就是负责保证可见性的。
63+
- 3、有序性,是保证线程内串行语义,避免指令重排等。
64+
65+
66+
### 02.多线程三要素
67+
#### 2.1 三要素分别是啥
68+
- 三要素分别是:原子性,可见性,有序性
69+
70+
71+
72+
#### 2.2 如何理解原子性
73+
- 如何理解原子性
74+
- 即一个操作(有可能包含有多个子操作)要么全部执行(生效),要么全部都不执行(都不生效)。
75+
- 举一个例子
76+
- 关于原子性,一个非常经典的例子就是银行转账问题:比如A和B同时向C转账10万元。如果转账操作不具有原子性,A在向C转账时,读取了C的余额为20万,然后加上转账的10万,计算出此时应该有30万,但还未来及将30万写回C的账户,此时B的转账请求过来了,B发现C的余额为20万,然后将其加10万并写回。然后A的转账操作继续——将30万写回C的余额。这种情况下C的最终余额为30万,而非预期的40万。
77+
78+
79+
80+
81+
#### 2.3 如何理解可见性
82+
- 如何理解可见性
83+
- 当多个线程并发访问共享变量时,一个线程对共享变量的修改,其它线程能够立即看到。
84+
- 举一个例子
85+
- CPU从主内存中读数据的效率相对来说不高,现在主流的计算机中,都有几级缓存。每个线程读取共享变量时,都会将该变量加载进其对应CPU的高速缓存里,修改该变量后,CPU会立即更新该缓存,但并不一定会立即将其写回主内存(实际上写回主内存的时间不可预期)。此时其它线程(尤其是不在同一个CPU上执行的线程)访问该变量时,从主内存中读到的就是旧的数据,而非第一个线程更新后的数据。这一点是操作系统或者说是硬件层面的机制,所以很多应用开发人员经常会忽略。
86+
87+
88+
89+
90+
#### 2.4 如何理解有序性
91+
- 如何理解有序性
92+
- 顺序性指的是,程序执行的顺序按照代码的先后顺序执行。
93+
- 举一个例子
94+
- 语句应该依次执行,但实际上JVM真正在执行这段代码时,并不保证它们一定完全按照此顺序执行。处理器为了提高程序整体的执行效率,可能会对代码进行优化,其中的一项优化方式就是调整代码顺序,按照更高效的顺序执行代码。CPU不按照我的代码顺序执行代码,那怎么保证得到我们想要的效果呢?实际上,CPU虽然并不保证完全按照代码顺序执行,但它会保证程序最终的执行结果和代码顺序执行时的结果一致。
95+
96+
97+
98+
99+
#### 2.5 三要素作用
100+
- 上面这三个要素主要作用是保障线程安全。保证线程安全可从多线程三特性出发:
101+
- 原子性(Atomicity):单个或多个操作是要么全部执行,要么都不执行
102+
- Lock:保证同时只有一个线程能拿到锁,并执行申请锁和释放锁的代码
103+
- synchronized:对线程加独占锁,被它修饰的类/方法/变量只允许一个线程访问
104+
- 可见性(Visibility):当一个线程修改了共享变量的值,其他线程能够立即得知这个修改
105+
- volatile:保证新值能立即同步到主内存,且每次使用前立即从主内存刷新;
106+
- synchronized:在释放锁之前会将工作内存新值更新到主存中
107+
- 有序性(Ordering):程序代码按照指令顺序执行
108+
- volatile: 本身就包含了禁止指令重排序的语义
109+
- synchronized:保证一个变量在同一个时刻只允许一条线程对其进行lock操作,使得持有同一个锁的两个同步块只能串行地进入
110+
111+
112+
113+
114+
115+
116+
### 其他介绍
117+
#### 01.关于博客汇总链接
118+
- 1.[技术博客汇总](https://www.jianshu.com/p/614cb839182c)
119+
- 2.[开源项目汇总](https://blog.csdn.net/m0_37700275/article/details/80863574)
120+
- 3.[生活博客汇总](https://blog.csdn.net/m0_37700275/article/details/79832978)
121+
- 4.[喜马拉雅音频汇总](https://www.jianshu.com/p/f665de16d1eb)
122+
- 5.[其他汇总](https://www.jianshu.com/p/53017c3fc75d)
123+
124+
125+
126+
#### 02.关于我的博客
127+
- github:https://github.com/yangchong211
128+
- 知乎:https://www.zhihu.com/people/yczbj/activities
129+
- 简书:http://www.jianshu.com/u/b7b2c6ed9284
130+
- csdn:http://my.csdn.net/m0_37700275
131+
- 喜马拉雅听书:http://www.ximalaya.com/zhubo/71989305/
132+
- 开源中国:https://my.oschina.net/zbj1618/blog
133+
- 泡在网上的日子:http://www.jcodecraeer.com/member/content_list.php?channelid=1
134+
135+
- 阿里云博客:https://yq.aliyun.com/users/article?spm=5176.100- 239.headeruserinfo.3.dT4bcV
136+
- segmentfault头条:https://segmentfault.com/u/xiangjianyu/articles
137+
- 掘金:https://juejin.im/user/5939433efe88c2006afa0c6e
138+
139+
140+
141+

0 commit comments

Comments
 (0)