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

作者:sherry_Rui 时间:2022-06-02 22:14:59 

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

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

第一个类:Account.java

账户类:


package cn.edu.byr.test;
public class Account {
private String accountNo;
private double balance;
public Account(){
}
public Account(String accountNo,double balance){
this.accountNo = accountNo;
this.balance = balance;
}
public int hashcode(){
return accountNo.hashCode();
}
public String getAccountNo(){
return this.accountNo;
}
public double getBalance(){
return this.balance;
}
public void setBalance(double balance){
this.balance = balance;
}
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;
}
}

第二个类:DrawThread.java

取钱线程类:


package cn.edu.byr.test;
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 e){
//         e.printStackTrace();
//       }
account.setBalance(account.getBalance() - drawAmount);
System.out.println("\t 余额为 : " + account.getBalance());
} else
       System.out.println(getName() + "取钱失败,余额不足!");
//   }
}
public static void main(String[] args){
Account acct = new Account("123456",1000);
new DrawThread("A",acct,800).start();
new DrawThread("B",acct,800).start();
}
}

上面代码中注释掉的部分:(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已经修改过的,会按照正确逻辑正常执行。

来源:http://blog.csdn.net/sherry_rui/article/details/51073114

标签:java,多线程,并发
0
投稿

猜你喜欢

  • redisson分布式限流RRateLimiter源码解析

    2021-05-29 13:10:15
  • Java设计模式之共享模式/享元模式(Flyweight模式)介绍

    2023-06-15 04:35:10
  • JAVA中阻止类的继承(官方和非官方)

    2023-06-29 16:02:56
  • android实现简单底部导航栏

    2022-07-10 16:11:08
  • Android简易音乐播放器实现代码

    2021-12-22 23:26:53
  • Android之ImageSwitcher的实例详解

    2022-06-08 06:03:14
  • 在springboot中实现个别bean懒加载的操作

    2023-11-25 09:44:11
  • java实现科研信息管理系统

    2022-05-13 02:49:41
  • @RequestBody,@RequestParam和@Param的区别说明

    2023-07-20 06:29:03
  • mybatis一直加载xml,找到错误的解决方案

    2022-08-12 14:55:26
  • 详解android进行异步更新UI的四种方式

    2023-12-24 19:46:55
  • Struts2中Action中是否需要实现Execute方法

    2021-10-30 06:57:23
  • 详解spring-boot actuator(监控)配置和使用

    2022-07-12 17:20:37
  • Java DelayQueue实现任务延时示例讲解

    2023-03-17 01:37:49
  • springboot整合mybatis实现简单的一对多级联查询功能

    2023-11-07 13:30:22
  • 弹出一个带确认和取消的dialog实例

    2023-11-22 06:07:13
  • Android自定义Notification添加点击事件

    2022-04-06 19:06:30
  • 详解Android的网络数据存储

    2022-08-22 01:39:39
  • C#使用windows服务开启应用程序的方法

    2022-08-14 04:37:14
  • 简单了解java标识符的作用和命名规则

    2022-06-18 17:49:09
  • asp之家 软件编程 m.aspxhome.com