• 多线程的线程同步(即上锁)


    线程同步


    • Java中的同步和异步
      • 同步:即加锁
        • Java中同步值的是不同时进行运行
    • Java中的异步
      • 异步:Java中的异步值同时进行
    1. 取钱案例出现问题的原因?
      • 多个线程同时执行,发现账户都是够钱的。
    2. 如何才能保证线程安全呢?
      • 让多个线程实现先后依次访问共享资源,这样就解决了安全问题

    线程同步核心思想


    • 加锁,把共享资源进行上锁,每次只能一个线程进入访问完毕以后解锁,然后其他线程才能进来。

    在这里插入图片描述

    • 线程同步解决安全问题的思想是什么?
      • 加锁:让多个线程实现先后依次访问共享资源,这样就解决了安全问题。

    方式一:同步代码块


    • 同步代码块
      • 作用:把出现线程安全问题的核心代码给上锁。
      • 原理:每次只能一个线程进入,执行完毕后自动解锁,其他线程才可以进来执行。
      • 格式:
    synchronized(同步锁对象) {
    	操作共享资源的代码(核心代码)
    }
    
    • 1
    • 2
    • 3
    • 锁对象要求

      • 理论上:锁对象只要对于当前同时执行的线程来说是同一个对象即可。
    • 锁对象用任意唯一的对象好不好呢?

      • 不好,会影响其他无关线程的执行。
    • 锁对象的规范要求

      • 规范上:建议使用共享资源作为锁对象。
      • 对于实例方法建议使用this作为锁对象。
      • 对于静态方法建议使用字节码(类名.class)对象作为锁对象。
    1. 同步代码块是如何实现线程安全的?
      • 对出现问题的核心代码使用synchronized进行加锁
      • 每次只能一个线程占锁进入访问
    2. 同步代码块的同步锁对象有什么要求?
      • 对于实例方法建议使用this作为锁对象。
      • 对于静态方法建议使用字节码(类名.class)对象作为锁对象。

    方式二:同步方法


    • 同步方法
      • 作用:把出现线程安全问题的核心方法给上锁。
      • 原理:每次只能一个线程进入,执行完毕以后自动解锁,其他线程才可以进来执行。
      • 格式:
    修饰符 synchronized 返回值类型 方法名称(形参列表) {
    		操作共享资源的代码
    	}
    
    • 1
    • 2
    • 3
    • 同步方法底层原理
      • 同步方法其实底层也是有隐式锁对象的,只是锁的范围是整个方法代码。
      • 如果方法是实例方法:同步方法默认用this作为的锁对象。但是代码要高度面向对象!
      • 如果方法是静态方法:同步方法默认用类名.class作为的锁对象。
    public class MoneyTest {  
        public static void main(String[] args) {  
            Account account = new Account("20220919",100000.0);  
      
            Thread mom = new DrawMoneyThread(account);  
            mom.setName("mom");  
            Thread son = new DrawMoneyThread(account);  
            son.setName("son");  
            mom.start();  
            son.start();  
      
            Account account1 = new Account("20220918",100000.0);  
      
            Thread dad = new DrawMoneyThread(account1);  
            dad.setName("dad");  
            Thread daughter = new DrawMoneyThread(account1);  
            daughter.setName("daughter");  
            dad.start();  
            daughter.start();  
        }  
    }  
    class DrawMoneyThread extends Thread{  
        private Account account;  
        public DrawMoneyThread(Account account) {  
            this.account = account;  
        }  
        @Override  
        public void run() {  
            account.drawMoney(100000);  
        }  
    }
    
    
    public class Account {  
        private String cardCode;  
        private double money;  
        private Object lock = new Object();  
        public Account() {  
      
        }  
      
        public synchronized void drawMoney(double money) {  
            System.out.println(Thread.currentThread().getName()+"准备取钱");  
            //synchronized (this) {  
                /*上锁  
                       显示锁:使用this可以直接锁住当前对象 即账户Accout  
                       隐式锁:写在方法的修饰符之后  
                           非静态方法:但是一定要是非静态方法锁住的也是当前的对象this  
                           静态方法:锁住的是当前的字节码(class)对象*/  
                if (this.money >= money) {  
                    System.out.println(Thread.currentThread().getName() + "您当前还有:" + this.money  
                            + "取出" + money);  
                    this.money -= money;  
                    System.out.println("成功取出" + money + "余额为:" + this.money);  
                } else {  
                    System.out.println("余额不足");  
                }  
            }  
      
      
        public Account(String cardCode, double money) {  
            this.cardCode = cardCode;  
            this.money = money;  
        }  
      
        public String getCardCode() {  
            return cardCode;  
        }  
      
        public void setCardCode(String cardCode) {  
            this.cardCode = cardCode;  
        }  
      
        public double getMoney() {  
            return money;  
        }  
      
        public void setMoney(double money) {  
            this.money = money;  
        }  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • ***上锁 ***

      • ***显示锁:使用this可以直接锁住当前对象 即账户Accout ***
      • ***隐式锁:写在方法的修饰符之后 ***
        • ***非静态方法:但是一定要是非静态方法锁住的也是当前的对象this ***
        • 静态方法:锁住的是当前的字节码(class)对象
    • 是同步代码块好还是同步方法好一点?

      • 同步代码块锁的范围更小,同步方法锁的范围更大。
  • 相关阅读:
    lvm磁盘管理
    【区块链 | Compound】3.剖析DeFi借贷产品之Compound:Subgraph篇
    【数据分析】Python:处理缺失值的常见方法
    Linux系统编程学习 NO.8 ——make和Makefile、进度条程序
    用python做一个压缩图片的小程序
    java:操作session
    吃透MySQL(十四):主从延时问题
    【iptables 实战】9 docker网络原理分析
    SpringBoot 整合Thymeleaf教程及使用
    飞书事件订阅的应用
  • 原文地址:https://blog.csdn.net/qq_72836797/article/details/126936522