多线程14:三大不安全案例

案例一:火车站买票

思路:

1.首先要有一个买票的类BuyTicket多线程要实现Runnable接口,重写run()里面是买票,

2.买票就需要有票,定义一个票的变量 private int ticketNums = 10;

3.写一个买票的方法buy():首先你得判断是否有票,if(ticketNums<=0),就停止return;

4.否则就买票,直接ticketNums--就可以了。谁+拿到+第几张票

5.然后需要一个循环,在while方法里面写,定义一个外部标志位,然后调用方法buy()买票

6.写主方法:首先去拿一张票,new一下拿到对象station,然后三个人(线程)操作同一个对象,new Thread(station,"苦逼的我").start,起名字开启线程,这样就可以拿到票了

7.检查一下代码:可以在判断是否有票那里模拟延时,放大问题的发生性。Thread.sleep(100);

package com.thread.syn;

//不安全的买票
//线程不安全,有负数?
//因为每个线程在自己的工作内存交互,内存控制不当会造成数据不一致。假如有3个人同时抢最后一张票,
//三个人买的时候看见都是1,都将1拷贝到自己内存了,第一个人买了,就变成0了,第二个人再买,就变成-1了。
public class UnsafeBuyTicket {

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

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

    }
}


class BuyTicket implements Runnable {

    //票
    private int ticketNums = 10;
    boolean flag = true;//外部停止方式

    @Override
    public void run() {

        //买票
        while (flag) {
            try {
                buy();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private void buy() throws InterruptedException {
        //判断是否有票
        if (ticketNums <= 0) {
            flag = false;
            return;
        }

        //模拟延时
        Thread.sleep(100);
        //买票
        System.out.println(Thread.currentThread().getName() + "拿到" + ticketNums--);
    }

}

结果:
牛逼的你们拿到10
可恶的黄牛党拿到8
苦逼的我拿到9
牛逼的你们拿到7
苦逼的我拿到6
可恶的黄牛党拿到5
牛逼的你们拿到4
苦逼的我拿到2
可恶的黄牛党拿到3
牛逼的你们拿到1
苦逼的我拿到0
可恶的黄牛党拿到-1

案例二:银行取钱

思路:

1.首先来个账户Account类,账户里面要有余额money ,还需要一个卡号name,来个构造方法Alt+Insert

2.银行:模拟取款Drawing,不安全继承一个Thread类,因为它不涉及到多个线程操作同一个对象。

首先有个账户,然后需要取了多少钱drawingMoney,还有个现在手里有多少钱nowMoney,自己写一个构造方法

3.重写run()方法,写取钱方法:

首先判断有没有钱,账户里面的钱-你要取得钱<0,就退出return;

说一句话,看一下 谁取得+钱不够,取不了

取钱这个操作具体怎么取:

首先账户的钱减少;卡内余额=余额-你取的钱

account.money = account.money-drawingMoney;

手里的钱:nowMoney =nowMoney+drawingMoney;

然后打印一下账户余额和手里的钱

4.去main方法里面写一下:

new 一个账户,100万的结婚基金,

然后你取钱,来一个账户account,取50万,你

你女朋友,也取account,取100万,你女朋友

然后开启两个线程,你和你对象都要取同一个账户里的钱

5.写一个延迟Thread.sleep(100),放大问题的发生性。

package com.thread.syn;

//不安全取钱
//两个人去银行取钱,账户有100万,你们两看见都是100万都可以取,
//但是一操作后就会出现负数,造成不安全的取钱。
//线程的内存都是各自的,互不影响,都是从原来的地方拷贝过去的。

public class UnsafeBank {
    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(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //卡内余额 = 余额 - 你取得钱
        account.money = account.money - drawingMoney;
        //你手里的钱
        nowMoney = nowMoney + drawingMoney;

        System.out.println(account.name + "余额为:" + account.money);
        //Thread.currentThread().getName() = this.getName()
        System.out.println(this.getName() + "手里的钱:" + nowMoney);

    }
}

结果:
结婚基金余额为:50
你手里的钱:50
结婚基金余额为:-50
girlFriend手里的钱:100

案例三:线程不安全的集合

package com.thread.syn;

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

//线程不安全的集合:
//因为两个线程,同一瞬间操作了同一个位置,把两个数组添加到了同一个位置,于是就把他覆盖掉了,元素就会少了
public class UnsafeList {

    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(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list.size());
    }
}

结果:
9993

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值