ACAC 线程同步机制(账户取款问题)

2、关于多线程并发环境下,数据的安全问题
 *        以后的开发中,项目运行在服务器当中,而服务器已经将线程的定义,线程对象的创建,线程的启动
 *      等实现了,我们不需要编写,但是,编写的程序需要放到一个多线程的环境下运行,
 *      需要关注的是这些数据在多线程并发的环境下是否是安全的,这是最重要的。
 *
 *      1、什么情况下回出现线程安全问题?
 *       1、多线程并发
 *       2、有共享数据
 *       3、共享数据有修改行为
 *     2、怎么解决这个问题?
 * 
 *       线程排队执行(不能并发),用排队执行解决线程安全问题,这种机制被称为:线程同步机制
 *       线程同步就是线程排队,排队就会牺牲一部分效率,但是数据安全第一位
 * 
 *     3、说到线程同步机制,有连个术语:
 *        异步编程模型:
 *          线程t1和线程t2,各自执行各自,谁也不管谁,其实就是对线程并发(效率较高)
 *        同步编程模型:
 *          线程t1和线程t2,在线程t1执行的时候,必须等等待t2线程执行结束,或者说在t2线程执行的
 *          时候,必须等待t1线程执行结束,两个线程之间发生了等待关系,这就是同步编程模型(效率较低,排队执行)
 *

package AccountThread;

public class Test {
    
    
    public static void main(String[] args) {
    
    
        //创建账户对象(只有一个)
        Account aa = new Account("asdff",10000);
        //创建两个线程
        Thread bb = new AccountThread(aa);
        Thread cc = new AccountThread(aa);

        bb.setName("线程一");
        cc.setName("线程二");
        bb.start();
        cc.start();

    }
}

package AccountThread;

public class AccountThread extends Thread{
    
    

    Account account;

    public AccountThread(Account account) {
    
    
        this.account = account;
    }

    @Override
    public void run() {
    
    
        //这里让一次取5000
        account.withdraw(5000);
    }
}

package AccountThread;

public class Account {
    
    
    private String username;
    private double balance;

    public Account() {
    
    
    }

    public Account(String username, double balance) {
    
    
        this.username = username;
        this.balance = balance;
    }

    public String getUsername() {
    
    
        return username;
    }

    public void setUsername(String username) {
    
    
        this.username = username;
    }

    public double getBalance() {
    
    
        return balance;
    }

    public void setBalance(double balance) {
    
    
        this.balance = balance;
    }

    public void withdraw(double money){
    
    
        //假如说线程一开始取钱时,执行到这里代码,还没有更新余额,线程二也开始执行run方法的withdraw方法
        //并比线程一快了一步,则线程二显示5000取款成功,还剩5000,而线程一也显示5000取款成功,还剩5000
        //这就是线程数据的安全问题


        /*
        问题很大,这种情况是随机的
        线程一5000取款成功,余额:5000.0
        线程二5000取款成功,余额:5000.0
        线程一5000取款成功,余额:0.0
        线程二5000取款成功,余额:0.0
        */


        //开始的钱
        double before = this.getBalance();

        //取钱
        double after = before - money;

        //更新余额,这里的确需要set和get方法,不让不好弄
        this.setBalance(after);
        System.out.println(Thread.currentThread().getName() +money+ "取款成功," + "余额:" + this.getBalance());
    }
}

猜你喜欢

转载自blog.csdn.net/qq_44707513/article/details/110749295