经典习题分析我们给出两个经典习题分析:
/*卖票问题*/// 源码展示:public class ExerciseSell {public static void main(String[] args) {TicketWindow ticketWindow = new TicketWindow(2000);List<Thread> list = new ArrayList<>();// 用来存储买出去多少张票List<Integer> sellCount = new Vector<>();for (int i = 0; i < 2000; i++) {Thread t = new Thread(() -> {// 分析这里的竞态条件int count = ticketWindow.sell(randomAmount());sellCount.add(count);});list.add(t);t.start();}list.forEach((t) -> {try {t.join();} catch (InterruptedException e) {e.printStackTrace();}});// 买出去的票求和log.debug("selled count:{}",sellCount.stream().mapToInt(c -> c).sum());// 剩余票数log.debug("remainder count:{}", ticketWindow.getCount());}// Random 为线程安全static Random random = new Random();// 随机 1~5public static int randomAmount() {return random.nextInt(5) + 1;}}// 卖票窗口class TicketWindow {// 票数,属于共享数据private int count;public TicketWindow(int count) {this.count = count;}public int getCount() {return count;}public int sell(int amount) {if (this.count >= amount) {this.count -= amount;return amount;} else {return 0;}}}// 问题分析:TicketWindow卖票窗口的票属于共享数据,对共享数据的修改需要进行上锁处理,所以我们需要对sell使用synchronized// 修改展示:public class ExerciseSell {public static void main(String[] args) {TicketWindow ticketWindow = new TicketWindow(2000);List<Thread> list = new ArrayList<>();List<Integer> sellCount = new Vector<>();for (int i = 0; i < 2000; i++) {Thread t = new Thread(() -> {int count = ticketWindow.sell(randomAmount());sellCount.add(count);});list.add(t);t.start();}list.forEach((t) -> {try {t.join();} catch (InterruptedException e) {e.printStackTrace();}});log.debug("selled count:{}",sellCount.stream().mapToInt(c -> c).sum());log.debug("remainder count:{}", ticketWindow.getCount());}static Random random = new Random();public static int randomAmount() {return random.nextInt(5) + 1;}}class TicketWindow {private int count;public TicketWindow(int count) {this.count = count;}public int getCount() {return count;}//在方法上加一个synchronized即可public synchronized int sell(int amount) {if (this.count >= amount) {this.count -= amount;return amount;} else {return 0;}}}
/*转账问题*/// 源码展示public class ExerciseTransfer {public static void main(String[] args) throws InterruptedException {Account a = new Account(1000);Account b = new Account(1000);Thread t1 = new Thread(() -> {for (int i = 0; i < 1000; i++) {a.transfer(b, randomAmount());}}, "t1");Thread t2 = new Thread(() -> {for (int i = 0; i < 1000; i++) {b.transfer(a, randomAmount());}}, "t2");t1.start();t2.start();t1.join();t2.join();// 查看转账2000次后的总金额log.debug("total:{}",(a.getMoney() + b.getMoney()));}// Random 为线程安全static Random random = new Random();// 随机 1~100public static int randomAmount() {return random.nextInt(100) +1;}}class Account {private int money;public Account(int money) {this.money = money;}public int getMoney() {return money;}public void setMoney(int money) {this.money = money;}public void transfer(Account target, int amount) {if (this.money > amount) {this.setMoney(this.getMoney() - amount);target.setMoney(target.getMoney() + amount);}}}// 问题分析:我们的transfer方法中存在两个对象,一个自身对象,一个被转账用户对象,所以无法使用synchronized方法但是我们可以暂时将他设置为 static synchronized 直接对账户整体进行上锁来处理问题~// 修改后代码:public class ExerciseTransfer {public static void main(String[] args) throws InterruptedException {Account a = new Account(1000);Account b = new Account(1000);Thread t1 = new Thread(() -> {for (int i = 0; i < 1000; i++) {a.transfer(b, randomAmount());}}, "t1");Thread t2 = new Thread(() -> {for (int i = 0; i < 1000; i++) {b.transfer(a, randomAmount());}}, "t2");t1.start();t2.start();t1.join();t2.join();log.debug("total:{}",(a.getMoney() + b.getMoney()));}static Random random = new Random();public static int randomAmount() {return random.nextInt(100) +1;}}class Account {private int money;public Account(int money) {this.money = money;}public int getMoney() {return money;}public void setMoney(int money) {this.money = money;}public static synchronized void transfer(Account target, int amount) {if (this.money > amount) {this.setMoney(this.getMoney() - amount);target.setMoney(target.getMoney() + amount);}}}
经验总结扩展阅读
- Seata Server 1.5.2 源码学习
- 2022极端高温!机器学习如何预测森林火灾?? 万物AI
- 1.nginx学习
- 常用Python库整理
- 2023年谷雨学习运有所提升的星座学业突飞猛进
- notability怎么一键清空手写笔记 notability怎么清除所有笔
- 图学习参考资料 词向量word2vec
- 五 RK3568开发笔记:在虚拟机上使用SDK编译制作uboot、kernel和ubuntu镜像
- realme笔记本最新消息_realme笔记本即将发布
- JUC学习笔记——进程与线程