• 多线程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);
     1 package com.thread.syn;
     2 
     3 //不安全的买票
     4 //线程不安全,有负数?
     5 //因为每个线程在自己的工作内存交互,内存控制不当会造成数据不一致。假如有3个人同时抢最后一张票,
     6 //三个人买的时候看见都是1,都将1拷贝到自己内存了,第一个人买了,就变成0了,第二个人再买,就变成-1了。
     7 public class UnsafeBuyTicket {
     8 
     9     public static void main(String[] args) {
    10         BuyTicket station = new BuyTicket();
    11 
    12         new Thread(station, "苦逼的我").start();
    13         new Thread(station, "牛逼的你们").start();
    14         new Thread(station, "可恶的黄牛党").start();
    15 
    16     }
    17 }
    18 
    19 
    20 class BuyTicket implements Runnable {
    21 
    22     //
    23     private int ticketNums = 10;
    24     boolean flag = true;//外部停止方式
    25 
    26     @Override
    27     public void run() {
    28 
    29         //买票
    30         while (flag) {
    31             try {
    32                 buy();
    33             } catch (InterruptedException e) {
    34                 e.printStackTrace();
    35             }
    36         }
    37     }
    38 
    39     private void buy() throws InterruptedException {
    40         //判断是否有票
    41         if (ticketNums <= 0) {
    42             flag = false;
    43             return;
    44         }
    45 
    46         //模拟延时
    47         Thread.sleep(100);
    48         //买票
    49         System.out.println(Thread.currentThread().getName() + "拿到" + ticketNums--);
    50     }
    51 
    52 }
    53 
    54 结果:
    55 牛逼的你们拿到10
    56 可恶的黄牛党拿到8
    57 苦逼的我拿到9
    58 牛逼的你们拿到7
    59 苦逼的我拿到6
    60 可恶的黄牛党拿到5
    61 牛逼的你们拿到4
    62 苦逼的我拿到2
    63 可恶的黄牛党拿到3
    64 牛逼的你们拿到1
    65 苦逼的我拿到0
    66 可恶的黄牛党拿到-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),放大问题的发生性。
     1 package com.thread.syn;
     2 
     3 //不安全取钱
     4 //两个人去银行取钱,账户有100万,你们两看见都是100万都可以取,
     5 //但是一操作后就会出现负数,造成不安全的取钱。
     6 //线程的内存都是各自的,互不影响,都是从原来的地方拷贝过去的。
     7 
     8 public class UnsafeBank {
     9     public static void main(String[] args) {
    10         //账户
    11         Account account = new Account(100, "结婚基金");
    12 
    13         Drawing you = new Drawing(account, 50, "你");
    14         Drawing girlFriend = new Drawing(account, 100, "girlFriend");
    15 
    16         you.start();
    17         girlFriend.start();
    18 
    19     }
    20 }
    21 
    22 
    23 //账户
    24 class Account {
    25     int money;//余额
    26     String name;//卡名
    27 
    28     public Account(int money, String name) {
    29         this.money = money;
    30         this.name = name;
    31     }
    32 }
    33 
    34 //银行:模拟取款
    35 class Drawing extends Thread {
    36 
    37     //账户
    38     Account account;
    39     //取了多少钱
    40     int drawingMoney;
    41     //现在手里有多少钱
    42     int nowMoney;
    43 
    44     public Drawing(Account account, int drawingMoney, String name) {
    45         super(name);
    46         this.account = account;
    47         this.drawingMoney = drawingMoney;
    48     }
    49 
    50     //取钱
    51 
    52     @Override
    53     public void run() {
    54 
    55         //判断有没有钱
    56         if (account.money - drawingMoney < 0) {
    57             System.out.println(Thread.currentThread().getName() + "钱不够,取不了");
    58             return;
    59         }
    60 
    61         try {
    62             Thread.sleep(100);
    63         } catch (InterruptedException e) {
    64             e.printStackTrace();
    65         }
    66 
    67         //卡内余额 = 余额 - 你取得钱
    68         account.money = account.money - drawingMoney;
    69         //你手里的钱
    70         nowMoney = nowMoney + drawingMoney;
    71 
    72         System.out.println(account.name + "余额为:" + account.money);
    73         //Thread.currentThread().getName() = this.getName()
    74         System.out.println(this.getName() + "手里的钱:" + nowMoney);
    75 
    76     }
    77 }
    78 
    79 结果:
    80 结婚基金余额为:50
    81 你手里的钱:50
    82 结婚基金余额为:-50
    83 girlFriend手里的钱:100
    案例三:线程不安全的集合
     1 package com.thread.syn;
     2 
     3 import java.util.ArrayList;
     4 import java.util.List;
     5 
     6 //线程不安全的集合:
     7 //因为两个线程,同一瞬间操作了同一个位置,把两个数组添加到了同一个位置,于是就把他覆盖掉了,元素就会少了
     8 public class UnsafeList {
     9 
    10     public static void main(String[] args) {
    11 
    12         List<String> list = new ArrayList<>();
    13         for (int i = 0; i < 10000; i++) {
    14             new Thread(() -> {
    15                 list.add(Thread.currentThread().getName());
    16             }).start();
    17         }
    18         try {
    19             Thread.sleep(3000);
    20         } catch (InterruptedException e) {
    21             e.printStackTrace();
    22         }
    23         System.out.println(list.size());
    24     }
    25 }
    26 
    27 结果:
    28 9993
  • 相关阅读:
    常用的Linux操作命令(一)
    本地绑定虚拟域名进行测试
    MVC定义路由
    Asp.Net请求处理机制中IsApiRuntime解析
    IOC
    数据库分页【Limt与Limt..OFFSET 】
    两个域名指向同一个网站
    WebApi服务以及跨域设置
    JS中小数的差,比较大小
    委托
  • 原文地址:https://www.cnblogs.com/duanfu/p/12260730.html
Copyright © 2020-2023  润新知