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

线程同步


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

线程同步核心思想


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

在这里插入图片描述

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

方式一:同步代码块


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

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

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

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

方式二:同步方法


  • 同步方法
    • 作用:把出现线程安全问题的核心方法给上锁。
    • 原理:每次只能一个线程进入,执行完毕以后自动解锁,其他线程才可以进来执行。
    • 格式:
修饰符 synchronized 返回值类型 方法名称(形参列表) {
		操作共享资源的代码
	}
  • 同步方法底层原理
    • 同步方法其实底层也是有隐式锁对象的,只是锁的范围是整个方法代码。
    • 如果方法是实例方法:同步方法默认用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;  
    }  
}
  • ***上锁 ***

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

    • 同步代码块锁的范围更小,同步方法锁的范围更大。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值