hbf548

多看源码多读书

0%

三大不安全案例

案例一(买票):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//不安全的买票
//线程不安全
public class BuyTicket implements Runnable{

//票
private int ticketNum = 10;

private boolean flag = true;


@Override
public void run() {
//买票
while (flag){
buy();
}
}

//买票
private void buy() {
//判断是否有票
if(ticketNum <= 0){
flag = false;
return;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "拿到第" + ticketNum-- + "张票");
}

public static void main(String[] args) {
BuyTicket buyTicket = new BuyTicket();

new Thread(buyTicket,"苦逼的我").start();
new Thread(buyTicket,"牛逼的你们").start();
new Thread(buyTicket,"可恶的黄牛党").start();
}
}

发现结果有很多种情况如复数,0,-1。或者两个人买到了同一张票
image.png
image.png

发现问题:

多个线程操作同一个资源的情况下,线程不安全,数据混乱。(拿到两个一样得东西 或者 拿到不存在的数据)

两个人买到同一张票好理解,但是这个复数和-1是怎么来的呢?
比如3个人(A,B,C)买票,因为没有锁,没有同步,3个人看到的都是第1票A买完就剩下0张,—-》A买了第1张
因为在A买最后一张票的时候,B看到的是1,所以依旧能够进行资源抢夺,所以A买完后剩下0张—-》B买了第0张票
同理C也是看到的是1张票,所以进入资源抢夺,B买完后,剩下-1,—》C买了第-1张票

案例二(银行取钱):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//不安全的取钱
//两个人去银行取钱,账户
public class SafeBank {
public static void main(String[] args) {
//账户
Account account = new Account(100, "结婚基金");

Drawing you = new Drawing(account, 50, "你");
Drawing girlfriend = new Drawing(account, 100, "girlfriend");

you.start();
girlfriend.start();
}
}


//账户
class Account{
int money; //余额
String name;//卡名

public Account(int money, String name) {
this.money = money;
this.name = name;
}
}


//银行:模拟取款
class Drawing extends Thread {

Account account;//账户
int drawingMoney;//取了多少钱
int nowmoney;//手里的钱

public Drawing(Account account, int drawingMoney, String name){
super(name);
this.account = account;
this.drawingMoney = drawingMoney;
}

//取钱
@Override
public void run() {
//判断有没有钱
if (account.money - drawingMoney <0){
System.out.println(Thread.currentThread().getName()+"钱不够,取不了");
return;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}

//卡内余额的钱 = 余额 - 取的钱
account.money = account.money - drawingMoney;

//手里的钱
nowmoney = nowmoney + drawingMoney;

System.out.println(account.name+"余额为:"+account.money);

//this.getName() == Thread.currentThread().getName() 因为 Drawing 继承了 Thread
System.out.println(this.getName()+"手里的钱为:"+account.money);


}
}


image.png

案例三:(集合不安全)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.hbf.demo01;

import java.util.ArrayList;
import java.util.List;

/**
* @Auther: Mr Li
* @Date: 20:17 2021/7/24
* @Description: com.hbf.demo01
* @version: 1.0
*/

//线程不安全集合
public class SafeList {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
for (int i = 0; i < 10000; i++) {

new Thread(()->{
list.add(Thread.currentThread().getName());
}).start();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}

image.png
应该是10000个才对!!