卖票

  1. package org.example.concurrency.test;
  2. import lombok.extern.slf4j.Slf4j;
  3. import java.util.ArrayList;
  4. import java.util.List;
  5. import java.util.Vector;
  6. /**
  7. * @author huskyui
  8. */
  9. @Slf4j
  10. public class ExerciseSell {
  11. public static void main(String[] args) {
  12. TicketWindow window = new TicketWindow(10000);
  13. //
  14. List<Integer> amountList = new Vector<>();
  15. List<Thread> threadList = new ArrayList<>();
  16. for (int i = 0;i<2000;i++){
  17. Thread thread = new Thread(()->{
  18. try {
  19. Thread.sleep(1);
  20. } catch (InterruptedException e) {
  21. e.printStackTrace();
  22. }
  23. int amount = window.sell(1);
  24. amountList.add(amount);
  25. });
  26. threadList.add(thread);
  27. thread.start();
  28. }
  29. threadList.forEach(t-> {
  30. try {
  31. t.join();
  32. } catch (InterruptedException e) {
  33. e.printStackTrace();
  34. }
  35. });
  36. log.info("余票:{}",window.getCount());
  37. int count = 0;
  38. for (int amount : amountList){
  39. count+=amount;
  40. }
  41. log.info(" 余票2 : {}",count);
  42. }
  43. }
  44. class TicketWindow{
  45. private int count;
  46. public TicketWindow(int count){
  47. this.count = count;
  48. }
  49. public int getCount(){
  50. return count;
  51. }
  52. // public synchronized int sell(int amount){
  53. // if(this.count >= amount){
  54. // this.count -=amount;
  55. // return amount;
  56. // }else{
  57. // return 0;
  58. // }
  59. // }
  60. public int sell(int amount){
  61. synchronized (this) {
  62. if (this.count >= amount) {
  63. this.count -= amount;
  64. return amount;
  65. } else {
  66. return 0;
  67. }
  68. }
  69. }
  70. }

我们可以看到,多个线程对一个对象进行竞争访问的时候,我们加入 关键字 synchronized 就可以锁定 当前创建的 TicketWindow window = new TicketWindow(10000);

转账

  1. package org.example.concurrency.test;
  2. import lombok.extern.slf4j.Slf4j;
  3. import java.util.Random;
  4. /**
  5. * @author huskyui
  6. */
  7. @Slf4j
  8. public class ExerciseTransfer {
  9. public static void main(String[] args) throws InterruptedException {
  10. Account account1 = new Account(1000);
  11. Account account2 = new Account(1000);
  12. Thread t1 = new Thread(() -> {
  13. for (int i = 0; i < 100; i++) {
  14. account1.transfer(account2, randomAmount());
  15. }
  16. }, "t1");
  17. Thread t2 = new Thread(() -> {
  18. for (int i = 0; i < 100; i++) {
  19. account2.transfer(account1, randomAmount());
  20. }
  21. }, "t2");
  22. t1.start();
  23. t2.start();
  24. t1.join();
  25. t2.join();
  26. log.info("余额 {}", account1.getMoney() + account2.getMoney());
  27. }
  28. // random 为线程安全
  29. static Random random = new Random();
  30. public static int randomAmount() {
  31. return random.nextInt(100) + 1;
  32. }
  33. }
  34. class Account {
  35. private int money;
  36. public Account(int money) {
  37. this.money = money;
  38. }
  39. public int getMoney() {
  40. return money;
  41. }
  42. public void setMoney(int money) {
  43. this.money = money;
  44. }
  45. public void transfer(Account target, int amount) {
  46. synchronized (Account.class) {
  47. if (this.money >= amount) {
  48. this.setMoney(this.getMoney() - amount);
  49. target.setMoney(target.getMoney() + amount);
  50. }
  51. }
  52. }
  53. }

我们可以转账时,我们需要同时给两个account对象加锁,我们如果还是想之前的方式,进行加锁就会出现问题

  1. public synchronized void transfer(Account target, int amount) {
  2. try {
  3. Thread.sleep(1);
  4. } catch (InterruptedException e) {
  5. e.printStackTrace();
  6. }
  7. if (this.money >= amount) {
  8. this.setMoney(this.getMoney() - amount);
  9. System.out.println(target.getMoney());
  10. target.setMoney(target.getMoney() + amount);
  11. }
  12. }

所以我们可以锁住Account.class这个类。但是这个效率低。