模拟取款

it2025-12-03  4

编写程序模拟2个线程同时对同一个账户进行取款操作

package com; /** * 银行账户 * 不使用线程同步机制,多线程对同一个账户进行取款,出现线程安全的问题。 */ class Account { //账户 private String actno; //余额 private double balance; public String getActno() { return actno; } public void setActno(String actno) { this.actno = actno; } public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } public Account() { } public Account(String actno, double balance) { this.actno = actno; this.balance = balance; } //取款的方法 public void withdraw(double money) { //t1和t2并发这个方法。t1和t2是2个栈,2个栈操作堆中的同一个对象 //取款之前的余额 double before = this.getBalance(); //取款后的余额 double after = before - money; //模拟网络延迟 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //更新账户 //思考:t1执行到这,但是还没来的急执行这行代码,t2线程进来withdraw方法。 this.setBalance(after); } } class MyThread extends Thread { //2个对象共享同一个账户 private Account act; //通过构造方法传递账户对象 public MyThread(Account act) { this.act = act; } @Override public void run() { //取款操作 double money = 5000; //取款 act.withdraw(money); System.out.println(Thread.currentThread().getName() +act.getActno() + "取款成功" + "余额" + act.getBalance()); } } class Test1 { public static void main(String[] args) { //创建账户对象 Account act = new Account("act-001", 10000); //创建2个线程 Thread t1 = new MyThread(act); Thread t2 = new MyThread(act); //设置线程名字 t1.setName("t1"); t2.setName("t2"); //启动线程取款 t1.start(); t2.start(); } } t1act-001取款成功余额5000.0 t2act-001取款成功余额5000.0

解决线程安全问题

package com; /** * 银行账户 * 使用线程同步机制,解决线程安全的问题。 */ class Account { //账户 private String actno; //余额 private double balance; public String getActno() { return actno; } public void setActno(String actno) { this.actno = actno; } public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } public Account() { } public Account(String actno, double balance) { this.actno = actno; this.balance = balance; } //取款的方法 public void withdraw(double money) { //这几行代码线程排队,不能并发 //取款之前的余额 /** * synchronized(){ * //线程同步代码块 * } * * ()中写什么? * 共享对象。假设t1,t2,t3,3个线程。只希望t1,t2排队。t3不排队,怎么办? * 你一定要在()中写一个t1,t2共享对象。而这个对象对于t3不是共享。 */ //这里共享对象是Account------>this synchronized (this){ double before = this.getBalance(); //取款后的余额 double after = before - money; //模拟网络延迟 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //更新账户 //思考:t1执行到这,但是还没来的急执行这行代码,t2线程进来withdraw方法。 this.setBalance(after); } } } class MyThread extends Thread { //2个对象共享同一个账户 private Account act; //通过构造方法传递账户对象 public MyThread(Account act) { this.act = act; } @Override public void run() { //取款操作 double money = 5000; //取款 act.withdraw(money); System.out.println(Thread.currentThread().getName() +"对"+act.getActno() + "进行"+money+"取款成功" + "余额" + act.getBalance()); } } class Test1 { public static void main(String[] args) { //创建账户对象 Account act = new Account("act-001", 10000); //创建2个线程 Thread t1 = new MyThread(act); Thread t2 = new MyThread(act); //设置线程名字 t1.setName("t1"); t2.setName("t2"); //启动线程取款 t1.start(); t2.start(); } } t1对act-001进行5000.0取款成功余额5000.0 t2对act-001进行5000.0取款成功余额0.0 //1、可以用synchronized (“abc”)在常量池,所以线程都同步 //2、在类定义成员变量:Object Obj=Object();---- synchronized (Obj) synchronized (this){//推荐 double before = this.getBalance(); //取款后的余额 double after = before - money; //模拟网络延迟 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //更新账户 //思考:t1执行到这,但是还没来的急执行这行代码,t2线程进来withdraw方法。 this.setBalance(after); } } }

以上执行原理是: 1、假设t1和t2线程并发,开始执行以下代码时候,肯定有一个先一个后。 2、假设t1先执行了,遇到了synchronized,这个时候自动找“后面共享对象”的对象锁。找到后, 并占有这把锁,然后执行同步代码块中的程序,在程序执行过程中一直都是占有这把锁,直至同步代码块代码结束,这把锁才会被释放。 3、假设t1已经占有这把锁,此时t2遇到synchronized关键字,也会去占有后面共享对象的这把锁,结果这把锁被t1占有,t2只能在同步代码块外面等待t1的结束,直到t1把同步代码块执行结束了,t1会归还这把锁,此时t2终于等到这把锁。然后t2占有这把锁后,进入同步代码块执行程序。 这样就实现了线程排队执行。 这里需要注意的是:这个共享对象一定要选好,这个共享对象一定是你需要排队执行的这些线程对象所共享的。

最新回复(0)