synchronized用法实战之银行取钱案例

本文探讨了如何使用synchronized解决线程同步问题,以银行取钱为例,解释了synchronized作为修饰符和同步块的两种用法,防止多个线程同时操作同一对象导致的数据错误。通过模拟多线程取款,展示了synchronized锁在确保数据安全上的应用。
摘要由CSDN通过智能技术生成

synchronized锁

解决线程同步机制的并发问题要用排队:队列 + 锁

两个线程同时争抢一个对象,可能会造成数据更新不及时.如两个人同时在一个银行账户取钱,钱取负数了

取钱

synchronized的两种用法

  • 用作修饰符时锁的是this(当前对象)

  • 作用就是锁住这个对象

  • 直到对象结束才释放让别人可以拿到这个锁


  • synchronized同步块锁变量时

  • 只有等这个变量操作完成才会释放

  • 当是由多条线程运行的多个线程操作一个变量的时候用这种方式

  • 所以一般用来锁住会变化的变量


银行取钱案例:多个线程同时操作同一个对象,造成数据出错后用synchronized锁来解决

思想

用一个static变量模拟银行账号的唯一性,同时有两个线程都来取钱

package com.li.changGe.multithreading.threadSafety;

public class SynchronizedDemo01 extends Thread{

    public static void main(String[] args) {
        SynchronizedDemo01 synchronizedDemo01 = new SynchronizedDemo01(100);
        SynchronizedDemo01 synchronizedDemo011 = new SynchronizedDemo01(100);

        /**
         * 继承Thread和实现Runnable本质上没有区别
         * 唯一的区别是继承Thread不强求实现run方法
         * Thread已经实现了,但是不代表不需要重写run方法
         * Thread底层的target初始为空
         * 
         * 归根结底只是java的继承和实现的区别
         *
         * 不过如果要实现一个对象运行两条线程建议用new Thread这种方式
         * 用同一个对象同时运行两个.start会报错:
         * IllegalThreadStateException(非法线程状态异常)
         */
        new Thread(synchronizedDemo01,"a").start();
        new Thread(synchronizedDemo011,"b").start();
        //new Thread(synchronizedDemo01,"b").start();

        //synchronizedDemo01.start();
        //synchronizedDemo01.start();
    }


    /**
     * 实现Runnable及其子类Thread后,idea为其在父类构造方法基础扩展属性
     * 构造方法不能被继承(自动调用):你继承Thread时能点出.Thread()方法吗?
     */
    public SynchronizedDemo01(Runnable target, double putMoney) {
        super(target);
        this.putMoney = putMoney;
    }

    /**
     * static修饰的对象只有一个
     * 就像银行的账号是唯一性的.
     * 
     * synchronized不允许传入基本类型
     * 用包装类底层会自动拆箱和装箱
     */
    private static Double balance = 100.0;

    public SynchronizedDemo01(double putMoney) {
        this.putMoney = putMoney;
    }

    /**
     * 取款数不固定
     * 后来的人会把前面人的取钱数覆盖
     */
    private /*static*/ double putMoney;

    @Override
    public void run() {
        putMoney(putMoney);
    }

    /**
     * 多个线程同时操作一个对象:
     * 两个人同时从一个账号中取钱
     *
     * 每个线程都会在自己的工作内存中交互:得到数据后放入一个自己(线程)中的一个空间操作
     * 且sleep时不会释放锁
     * 造成余额出现负数的情况
     */
    /**
     * 每个对象都有一把锁
     * synchronized用作修饰符时锁的是this(当前对象)
     * 它的作用就是锁住这个对象,直到对象结束才释放让别人可以拿到这个锁
     */
    public /*synchronized*/ void putMoney(double putMoney){
        /**
         * synchronized同步块锁变量时,
         * 只有等这个变量操作完成才会释放
         *
         * 当是由多条线程运行的多个线程操作一个变量的时候用这种方式
         * 所以一般用来锁住会变化的变量
         */
         /**
         * 锁方法会有弊端:
         * 一段代码中,A段代码只负责读,B段代码只负责写
         * 方法被锁住后,读写不分离了.
         */
        synchronized (balance) {
            /**
             * 因为继承了Thread
             * 就可以直接使用Thread的getName()方法
             */
            System.out.println(this.getName()+"进来取钱了,余额为"+ balance);
            if (balance < putMoney) {
                System.out.println("钱不够了");
            } else {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                balance -= putMoney;
                System.out.println(Thread.currentThread().getName() + "取走" + putMoney
                    + ",还有" + balance);
            }//else
            return;

        }//synchronized
    }//putMoney

}

synchronized取钱

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

helloses

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值