多线程不安全案例(不安全&synchronized同步解决):买票,银行取钱

同步可以看成排队
每个线程进入同步队列,进行操作时出队,想要继续操作时入队进行等待
如果线程不排队,一拥而上,资源根本不够分配,而且执行的速度够快,无法保证数据的统一性

synchronized:

  • 声明方法:锁定当前方法,每个线程使用该方法时都要排队
  • 锁定对象:在操作当前对象时,要排队
Runnable和Thread都能实现资源共享 不要被误导

卖门票

public class UnsafeTicket {
    public static void main(String[] args) {
        BuyTicket buyTicket=new BuyTicket();
        new Thread(buyTicket,"小明").start();
        new Thread(buyTicket,"张三").start();
        new Thread(buyTicket,"黄牛").start();
    }
}
class BuyTicket implements Runnable{
    private boolean flag=true;
    int num=10;
    @Override
    public void run() {
        while(flag){
           buy();
        }
    }
    public void stop(){//标识符停止
        this.flag=false;
    }
}

对买票这个行为来说,票是共享资源 ,所以要考虑的就是如何控制票数 
所以就要对买票行为加上同步锁 防止三个线程抢占式买票,导致票的数据不一致性
提醒:现在的电脑性能过高 为了体现多人抢票,最好在购票前加上线程睡眠,以免出现一人全抢的情况
(一个线程调度运行,在这个线程运行至运行完的过程中,其他线程未被调度甚至调度了还没开始跑的情况)
未加同步的买票
    public void buy(){
        if(num<=0){
            stop();
            System.out.println("卖完了");
            return;
        }
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"买了第"+num--);
    }

在这里插入图片描述
7、5、3、1被同时购买,没有票后还买了张0,所以线程不安全

加上同步的买票
 //buy操作共享票资源 所以对buy加上同步
    public synchronized void buy(){
        if(num<=0){
            stop();
            //System.out.println("卖完了");
            return;
        }
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"买了第"+num--);
    }

在这里插入图片描述

  • 加上同步后 每次进行买票操作,三个线程被cpu安排 进入同步队列,依次出队买票 ,以及入队等待买票 不会出现两人同时买票以及买同一张的结果

银行取钱

public class UnsafeBank {
    public static void main(String[] args) {
        Account account=new Account(100,"结婚基金");

        Arawing you=new Arawing(account,50,"你");
        Arawing love=new Arawing(account,70,"妻子");
        you.start();
        love.start();
    }
}
class Account {
    int money;//余额
    String name;//账户

    public Account(int money, String name) {

        this.money = money;
        this.name = name;
    }
}
class Arawing extends Thread{
    Account account;//账户
    int arawingMoney;
    int nowMoney;
    String name;
    public Arawing(Account accout,int arawingMoney,String name){
        super(name);
        this.account=accout;
        this.arawingMoney=arawingMoney;

    }

    @Override
    public void run() {
        //银行共享账户资源 对账户加上同步
        synchronized(account) {
            if (account.money - arawingMoney < 0) {
                System.out.println(Thread.currentThread().getName() + "余额不足");
                return;
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            account.money = account.money - arawingMoney;
            nowMoney = nowMoney + arawingMoney;
        }
        //System.out.println(Thread.currentThread().getName()+"取了"+arawingMoney);
        System.out.println(this.getName()+"手上有"+nowMoney);
        System.out.println("余额"+account.money);
    }
}

因为多个人同时使用同一账户取钱,所以该案列需要同步的并非银行,而是账户 同步看成排队

两人同时用同一账户取钱,我在取的时候,       
在另一个银行的取钱的妻子,取钱系统必须等待我这边取完才能运行

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值