您好,登录后才能下订单哦!
这篇文章主要为大家展示了“Java同步代码块如何解决银行取钱的安全问题”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Java同步代码块如何解决银行取钱的安全问题”这篇文章吧。
具体如下:
一 点睛
为了解决类似银行取钱这类安全问题,Java的多线程支持引入了同步监视器来解决这个问题,使用同步监视器的通用方法是同步代码块。同步代码块的语法格式是:
synchronized(obj) { //此处代码块就是同步代码块。 }
上面语法格式中种的obj就是同步监视器,上面代码的含义是:线程开始执行同步代码块之前,必须先获得对同步监视器的锁定。
任何时刻只能由一个线程获得对同步监视器的锁定,当同步代码块执行完成后,该线程会释放对该同步监视器的锁定。
虽然Java程序允许使用任何对象作为同步监视器,但想一下同步监视器的目的:阻止两个线程对同一共享资源进行并发访问,因此通常推荐使用可能被并发访问的共享资源作为同步监视器。
二 代码
1 定义一个账户类
public class Account { // 封装账户编号、账户余额的两个成员变量 private String accountNo; private double balance; public Account(){} // 构造器 public Account(String accountNo , double balance) { this.accountNo = accountNo; this.balance = balance; } // 此处省略了accountNo和balance的setter和getter方法 // accountNo的setter和getter方法 public void setAccountNo(String accountNo) { this.accountNo = accountNo; } public String getAccountNo() { return this.accountNo; } // balance的setter和getter方法 public void setBalance(double balance) { this.balance = balance; } public double getBalance() { return this.balance; } // 下面两个方法根据accountNo来重写hashCode()和equals()方法 public int hashCode() { return accountNo.hashCode(); } public boolean equals(Object obj) { if(this == obj) return true; if (obj !=null && obj.getClass() == Account.class) { Account target = (Account)obj; return target.getAccountNo().equals(accountNo); } return false; } }
2 定义一个取钱线程
public class DrawThread extends Thread { // 模拟用户账户 private Account account; // 当前取钱线程所希望取的钱数 private double drawAmount; public DrawThread(String name, Account account, double drawAmount) { super(name); this.account = account; this.drawAmount = drawAmount; } // 当多条线程修改同一个共享数据时,将涉及数据安全问题。 public void run() { synchronized (account) { // 账户余额大于取钱数目 if (account.getBalance() >= drawAmount) { // 吐出钞票 System.out.println(getName() + "取钱成功!吐出钞票:" + drawAmount); try { Thread.sleep(1); } catch (InterruptedException ex) { ex.printStackTrace(); } // 修改余额 account.setBalance(account.getBalance() - drawAmount); System.out.println("\t余额为: " + account.getBalance()); } else { System.out.println(getName() + "取钱失败!余额不足!"); } } } }
3 测试主类
public class DrawTest { public static void main(String[] args) { // 创建一个账户 Account acct = new Account("1234567" , 1000); // 模拟两个线程对同一个账户取钱 new DrawThread("甲" , acct , 800).start(); new DrawThread("乙" , acct , 800).start(); } }
三 运行
甲取钱成功!吐出钞票:800.0
余额为: 200.0
乙取钱失败!余额不足!
四 说明
使用synchronized将run()方法里的方法体修改为同步代码块,该同步代码块的同步监视器是account对象,这样的做法符合“加锁->修改->释放锁”的逻辑,任何线程在修改指定资源之前,首先对该资源加锁,在加锁期间其他线程无法修改该资源,当该线程修改完成后,该线程释放对该资源的锁定。通过这种方式就可以保证并发线程任一时刻只有一个线程可以进入修改共享资源的代码区(也称临界区),所以同一时刻最多只有一个线程处于临界区,从而保证线程的安全。
以上是“Java同步代码块如何解决银行取钱的安全问题”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。