多线程三种同步方式(模拟银行取款)

方法一:同步代码块

Accoun

package com.bjsxt.synch1;

/**
 * 银行账户类
 */
public class Account {
    private int balance = 600;//余额

    /**
     * 取款
     * @param money
     */
    public void withDraw(int money){
        this.balance = this.balance -money;
    }

    /**
     * 查看余额
     * @return
     */
    public int getBalance(){
        return balance;
    }
}

取款线程

package com.bjsxt.synch1;

/**
 * 取款的线程
 *
 * 线程同步方式1:同步代码块
 *
 * 总结1:认识同步监视器(锁子)
 *     synchronized(同步监视器){ }
 * 1)必须是引用数据类型,不能是基本数据类型
 * 2)在同步代码块中可以改变同步监视器对象的值,不能改变其引用
 * 3)尽量不要String和包装类Integer做同步监视器.如果使用了,只要保证代码块中不对其进行任何操作也没有关系
 * 4)一般使用共享资源做同步监视器即可
 * 5)也可以创建一个专门的同步监视器,没有任何业务含义
 * 6)建议使用final修饰同步监视器
 *
 * 总结2:同步代码块的执行过程
 * 1)第一个线程来到同步代码块,发现同步监视器open状态,需要close,然后执行其中的代码
 * 2)第一个线程执行过程中,发生了线程切换(阻塞 就绪),第一个线程失去了cpu,但是没有开锁open
 * 3)第二个线程获取了cpu,来到了同步代码块,发现同步监视器close状态,无法执行其中的代码,第二个线程也进入阻塞状态
 * 4)第一个线程再次获取CPU,接着执行后续的代码;同步代码块执行完毕,释放锁open
 * 5)第二个线程也再次获取cpu,来到了同步代码块,发现同步监视器open状态,重复第一个线程的处理过程(加锁)
 * 强调:同步代码块中能发生线程切换吗?能!!! 但是后续的被执行的线程也无法执行同步代码块(锁仍旧close)

 * 总结3:线程同步 优点和缺点
 *     优点:安全
 *     缺点:效率低下  可能出现死锁
 *    
 * 总结4:其他
 * 1)多个代码块使用了同一个同步监视器(锁),锁住一个代码块的同时,也锁住所有使用该锁的所有代码块,其他线程无法访问其中的任何一个代码块
 * 2)多个代码块使用了同一个同步监视器(锁),锁住一个代码块的同时,也锁住所有使用该锁的所有代码块, 但是没有锁住使用其他同步监视器的代码块,其他线程有机会访问其他同步监视器的代码块

 */
public class AccountRunnable implements  Runnable{
    private final  Account account = new Account();
    final Object obj = new Object();
    //byte [] buf = new byte[1];
    //final String str = "bjsxt";
    //final Integer in = 1234;

    //int n = 5;
    /**
     * 线程体:取款的步骤
     */
    @Override
    public void run() {
        //此处省略200句
 
        synchronized (account){
            if(account.getBalance()>=400){//余额足够  临界代码
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //就取款
                account.withDraw(400);
                System.out.println(Thread.currentThread().getName()+"取款成功,当前余额:"+account.getBalance());

            }else{//余额不足
                //给出提示
                System.out.println(Thread.currentThread().getName()+"取款失败,余额不足,当前余额:"+account.getBalance());
            }
        }

        //此处省略100句
    }

    public void method1(){
        synchronized (account){

        }


    }

    public void method2(){

        synchronized (obj){

        }


    }

    public void method3(){
        synchronized (obj){

        }


    }
}

main

package com.bjsxt.synch1;

public class TestAccount {
    public static void main(String[] args) {
        //创建两个线程,模拟两个用户
        Runnable runnable = new AccountRunnable();
        Thread thread1 = new Thread(runnable,"张三");
        Thread thread2 = new Thread(runnable,"张三妻子");

        //启动两个线程,模拟两个用户取款
        thread1.start();
        thread2.start();
    }
}

方法二:同步方法

银行账户类

package com.bjsxt.synch2;

/**
 * 银行账户类
 */
public class Account {
    private int balance = 600;//余额

    /**
     * 取款
     * @param money
     */
    public void withDraw(int money){
        this.balance = this.balance -money;
    }

    /**
     * 查看余额
     * @return
     */
    public int getBalance(){
        return balance;
    }
}

取款的线程

package com.bjsxt.synch2;

/**
 * 取款的线程
 *方式2:同步方法
 *
 * 1.不要给run()加锁
 * 2. 非静态同步方法的锁:this
 *    静态同步方法的锁:类名.class
 * 3.同步方法和同步代码块哪种效率高
 *    同步代码块效率高
 *
 */
public class AccountRunnable implements  Runnable{
    private Account account = new Account();
    /**
     * 线程体:取款的步骤
     */
    @Override
    public  void run() {
        //此处省略200句

        //取款
        withDraw();

        //此处省略100句
    }

    public synchronized void withDraw(){      //非静态同步方法的锁是this
        if(account.getBalance()>=400){       //余额足够  临界代码
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //就取款
            account.withDraw(400);
            System.out.println(Thread.currentThread().getName()+"取款成功,当前余额:"+account.getBalance());

        }else{//余额不足
            //给出提示
            System.out.println(Thread.currentThread().getName()+"取款失败,余额不足,当前余额:"+account.getBalance());
        }
    }

    public synchronized  void method1(){ //this

    }
    public synchronized  void method2(){ //this
        // Vector v;
    }

    public synchronized  static void method3(){ //静态的同步方法的锁是类名.class 类对象 AccountRunnable.class
        //Class clazz =  AccountRunnable.class;
    }

    public synchronized static void method4(){

    }
}

main

package com.bjsxt.synch2;

public class TestAccount {
    public static void main(String[] args) {
        //创建两个线程,模拟两个用户
        Runnable runnable = new AccountRunnable();
        Thread thread1 = new Thread(runnable,"张三");
        Thread thread2 = new Thread(runnable,"张三妻子");

        //启动两个线程,模拟两个用户取款
        thread1.start();
        thread2.start();
    }
}

方法三:锁

银行账户类

package com.bjsxt.synch3;

/**
 * 银行账户类
 */
public class Account {
    private int balance = 600;//余额

    /**
     * 取款
     * @param money
     */
    public void withDraw(int money){
        this.balance = this.balance -money;
    }

    /**
     * 查看余额
     * @return
     */
    public int getBalance(){
        return balance;
    }
}

取款的线程

package com.bjsxt.synch3;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 取款的线程
 */
public class AccountRunnable implements  Runnable{
    private Account account = new Account();

    //购买一把锁
    private Lock lock = new ReentrantLock();//Re-entrant-Lock  //entrance 可重入锁
    /**
     * 线程体:取款的步骤
     */
    @Override
    public void run() {
        //此处省略200句

        //上锁
        lock.lock();
        try{
            if(account.getBalance()>=400){//余额足够  临界代码
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //就取款
                account.withDraw(400);
                System.out.println(Thread.currentThread().getName()+"取款成功,当前余额:"+account.getBalance());

            }else{//余额不足
                //给出提示
                System.out.println(Thread.currentThread().getName()+"取款失败,余额不足,当前余额:"+account.getBalance());
            }
            method1();
        }finally{
            //解锁
            lock.unlock();
        }




        //此处省略100句
    }

    public void method1(){

        lock.lock();
        try{
            method2();
        }finally{
            lock.unlock();
        }


    }

    public void method2(){
        lock.lock();
        try{

        }finally{
            lock.unlock();
        }
    }
}

main

package com.bjsxt.synch3;

public class TestAccount {
    public static void main(String[] args) {
        //创建两个线程,模拟两个用户
        Runnable runnable = new AccountRunnable();
        Thread thread1 = new Thread(runnable,"张三");
        Thread thread2 = new Thread(runnable,"张三妻子");

        //启动两个线程,模拟两个用户取款
        thread1.start();
        thread2.start();
    }
}

  • 2
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
这个情况需要考虑多线同步,以防止两个用户同时对同一个账户进行取款操作,导致数据错误。 可以使用锁机制来实现多线同步。具体做法如下: 1. 定义一个共享变量account表示银行账户余额,初值为2000元。 2. 定义一个锁对象lock。 3. 定义两个线程对象,分别表示两个用户。 4. 在每个用户线程中,使用for循环进行4次取款操作,每次取款100元。 5. 在取款操作中,先获取锁对象lock,确保当前用户可以对账户进行取款操作,然后再进行取款操作。 6. 取款操作完成后,释放锁对象lock,让其他用户可以对账户进行取款操作。 代码实现如下: ```python import threading account = 2000 lock = threading.Lock() class User(threading.Thread): def __init__(self, name): super().__init__() self.name = name def run(self): global account for i in range(4): lock.acquire() if account >= 100: account -= 100 print(f"{self.name}取款100元,余额{account}元") else: print(f"{self.name}取款失败,余额不足") lock.release() user1 = User("User1") user2 = User("User2") user1.start() user2.start() user1.join() user2.join() print(f"最终余额:{account}元") ``` 运行结果如下: ``` User1取款100元,余额1900元 User2取款100元,余额1800元 User1取款100元,余额1700元 User2取款100元,余额1600元 User1取款100元,余额1500元 User2取款100元,余额1400元 User1取款100元,余额1300元 User2取款100元,余额1200元 User1取款100元,余额1100元 User2取款100元,余额1000元 User1取款100元,余额900元 User2取款100元,余额800元 User1取款100元,余额700元 User2取款100元,余额600元 User1取款100元,余额500元 User2取款100元,余额400元 User1取款100元,余额300元 User2取款100元,余额200元 User1取款100元,余额100元 User2取款失败,余额不足 最终余额:100元 ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

AloneDrifters

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

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

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

打赏作者

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

抵扣说明:

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

余额充值