案例一:火车站买票
思路:
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