中国领先的工业平台

返回贤集网 返回微头条
贤集网技术微头条APP获取

java编程多线程并发处理实例解析

 山东大明消毒科技有限公司

下载贤集网APP入驻自媒体

本文主要是通过一个银行用户取钱的实例,演示java编程多线程并发处理场景,具体如下。

从一个例子入手:实现一个银行账户取钱场景的实例代码。

第一个类:Account.java

账户类:

  1. package cn.edu.byr.test;
  2. public class Account {
  3. private String accountNo;
  4. private double balance;
  5. public Account(){
  6. }
  7. public Account(String accountNo,double balance){
  8. this.accountNo = accountNo;
  9. this.balance = balance;
  10. }
  11. public int hashcode(){
  12. return accountNo.hashCode();
  13. }
  14. public String getAccountNo(){
  15. return this.accountNo;
  16. }
  17. public double getBalance(){
  18. return this.balance;
  19. }
  20. public void setBalance(double balance){
  21. this.balance = balance;
  22. }
  23. public Boolean equals(Object obj){
  24. if(this == obj)
  25. return true;
  26. if(obj != null && obj.getClass() == Account.class){
  27. Account target = (Account)obj;
  28. return target.getAccountNo().equals(accountNo);
  29. }
  30. return false;
  31. }
  32. }
复制代码

第二个类:DrawThread.java

取钱线程类:

  1. package cn.edu.byr.test;
  2. public class DrawThread extends Thread {
  3. private Account account;
  4. private double drawAmount;
  5. public DrawThread(String name,Account account,double drawAmount){
  6. super(name);
  7. this.account = account;
  8. this.drawAmount = drawAmount;
  9. }
  10. public void run(){
  11. // synchronized (account) {
  12. if(account.getBalance() > drawAmount){
  13. System.out.println(getName() + "取钱成功,吐出钞票:" + drawAmount);
  14. // try{
  15. // Thread.sleep(1);
  16. // }
  17. // catch(InterruptedException e){
  18. // e.printStackTrace();
  19. // }
  20. account.setBalance(account.getBalance() - drawAmount);
  21. System.out.println("\t 余额为 : " + account.getBalance());
  22. } else
  23. System.out.println(getName() + "取钱失败,余额不足!");
  24. // }
  25. }
  26. public static void main(String[] args){
  27. Account acct = new Account("123456",1000);
  28. new DrawThread("A",acct,800).start();
  29. new DrawThread("B",acct,800).start();
  30. }
  31. }
复制代码

上面代码中注释掉的部分:(1)synchronized同步代码块 (2)线程休眠。如果注释掉(1)、(2),则运行结果有多种可能性,可能性之一(概率较小),符合正常逻辑:

B取钱成功,吐出钞票:800.0
余额为 : 200.0
A取钱失败,余额不足!

应该是B先强找到取钱资源,并且正确修改余额后,A才开始判断用户余额;这种概率非常小,多数运行会类似以下情况:

A取钱成功,吐出钞票:800.0
B取钱成功,吐出钞票:800.0
余额为 : -600.0
余额为 : 200.0

这明显是不符合逻辑的,从运行结果可以猜测,A先抢占资源,取出金额,但在修改余额之前,资源被B抢占;由于余额未被修改,则B看到余额仍然是800,B仍然取出金额;A先运行修改余额,但并未打印,B抢夺资源;B修改余额,并打印余额,为-600;A打印余额,为200;

如果加上(2)线程休眠,则一定是错误状况,因为A或B在取出金额后一定会因为sleep释放CPU资源,JVM会调用其他处于准备状态的进程。第二个取钱判断余额一定是错误的。

如果加上(1)synchronized同步代码块,在线程run方法体中对account进行加锁;则每次都会保证执行逻辑正常:

A取钱成功,吐出钞票:800.0
余额为 : 200.0
B取钱失败,余额不足!
可以设想一下执行过程:

A先抢占资源,在run方法体初始对account类进行加锁;然后开始执行同步代码块;如果执行到中间某个环节,CPU资源被B抢占;B开始执行,一开始也会对account类进行加锁。但是加锁时会发现account已经被A占用,则会调整为阻塞状态等待A释放资源;A执行完同步代码块后释放account的锁,B继续执行;B运行时看到的余额保证是A已经修改过的,会按照正确逻辑正常执行。

最新回复

还没有人回复哦,抢沙发吧~

发布回复

为您推荐

热门交流