zl程序教程

您现在的位置是:首页 >  其他

当前栏目

银行取款[多线程]{未进行线程同步}(junit不适合多线程并发单元测试)

多线程同步junit并发线程 进行 适合 单元测试
2023-09-14 09:04:40 时间
        由于计算机多任务、多进程、多线程的支持,使得计算机资源的服务效率提高,服务器对请求的也使用线程来相应,所有,代码中涉及到同时对共享数据的操作,将在 多线程环境中操作数据,导致数据安全问题。      经典例子:老婆(朱丽叶)老公(罗密欧),使用银行卡和存折,或者网银等,同时对同一账户操作的安全问题。      如果要保证多线程下数据安全,就要实现线程同步(例如:一

        由于计算机多任务、多进程、多线程的支持,使得计算机资源的服务效率提高,服务器对请求的也使用线程来相应,所有,代码中涉及到同时对共享数据的操作,将在

多线程环境中操作数据,导致数据安全问题。

     经典例子:老婆(朱丽叶)老公(罗密欧),使用银行卡和存折,或者网银等,同时对同一账户操作的安全问题。

     如果要保证多线程下数据安全,就要实现线程同步(例如:一间小厕所,就得有一个锁,保证同一时间为一个人服务)。其他文章讲:

此处用多线程实现,同时取款的模拟实现,未进行线程同步操作,查看取款安全隐患问题,代码如下:

银行账户:

package com.tsxs.bank;

public class BankAccount {

 //余额

 private int balance = 500;

 //查询

 public int getBalance(){

 return banlance;

 //取款

 public void withdraw(int amount){

 banlance = banlance - amount;

 //存款

 public void deposit(int amount){

 banlance = banlance + amount;

线程类:

package com.tsxs.syncmethods;

import com.tsxs.bank.BankAccount;

 * 此线程类实现Runnable接口

 * 未进行线程同步 

 * */

public class NoSync implements Runnable{

 //所有Thread多线程线程都共享Runnable(接口对象)和account对象

 private BankAccount account = new BankAccount();

 @Override

 public void run() {

 for(int i = 0; i i++){ //总共取款5次

 makeWithdraw(100); //每次取款100

 if(account.getBalance() 0){

 System.out.println(""+Thread.currentThread().getName()+" 透支了!");

 * makeWithdraw 账户取款

 * @param amount 取款金额 br / 

 * 打印log记录取款过程

 * */

 private void makeWithdraw(int amount){

 if(account.getBalance() = amount){ //如果余额足够则取款

 System.out.println(""+Thread.currentThread().getName()+" 准备取款!");

 try {

 Thread.sleep(500);

 } catch (InterruptedException e) {

 System.out.println(Thread.currentThread().getName()+" 准备取款,等待0.5s线程中断!"+e.getMessage());

 account.withdraw(amount);

 System.out.println(""+Thread.currentThread().getName()+" 完成"+amount+"取款!余额为"+account.getBalance());

 }else{ //余额不足则提示

 System.out.println(""+"余额不足以支付"+Thread.currentThread().getName()+amount+" 的取款,余额为"+account.getBalance());


测试代码:

package com.tsxs.test;

import org.junit.Test;

import com.tsxs.syncmethods.NoSync;

public class TreadSyncTest {

// @Test

// public void test() {

/*Junit不适合多线程并发测试。

 因为线程还在激活状态的时候,Junit已经执行完成。

 在Junit的TestRunner中,它没有被设计成搜寻Runnable实例,

 并且等待这些线程发出报告,它只是执行它们并且忽略了它们的存在。

 综上,不可能在Junit中编写和维护多线程的单元测试。

 public static void main(String[] args) {

 //实现Runnable:所有Thread多线程线程都共享Runnable(接口对象)

 NoSync target =new NoSync();

 //创建李琦和他老婆两个线程实现取款(同时)

 Thread lq = new Thread(target);

 lq.setName("罗密欧");

 Thread lqwf = new Thread(target);

 lqwf.setName("朱丽叶");

 //调用Thread对象的start()方法,启动线程,执行run()方法(OS)

 lq.start();

 lqwf.start();


打印log记录为:

朱丽叶   准备取款!

罗密欧   准备取款!

朱丽叶   完成100取款!余额为400

罗密欧   完成100取款!余额为400

罗密欧   准备取款!

朱丽叶   准备取款!

朱丽叶   完成100取款!余额为200

罗密欧   完成100取款!余额为200

朱丽叶   准备取款!

罗密欧   准备取款!

朱丽叶   完成100取款!余额为100

罗密欧   完成100取款!余额为100

朱丽叶   准备取款!

罗密欧   准备取款!

罗密欧   完成100取款!余额为-100

朱丽叶   完成100取款!余额为-100

朱丽叶   透支了!

余额不足以支付朱丽叶100   的取款,余额为-100

朱丽叶   透支了!

罗密欧   透支了!

余额不足以支付罗密欧100   的取款,余额为-100

罗密欧   透支了!

分析结果,可见:

双线程总共取款10次,账户总额为500.

取款结果:取款成功600元,余额显示不对,最终账户余额为-100,已透支。

现实中,此取款代码是有严重bug的,上边数据对于银行是危险的,个人也会带来不必要的麻烦。


Gradle从0入门到实战系列【八】SpringBoot集成Junit单元测试 JUnit 是一个 Java 编程语言的单元测试框架。JUnit 在测试驱动的开发方面有很重要的发展,是起源于 JUnit 的一个统称为 xUnit 的单元测试框架之一。
Java程序员必须要知道的单元测试框架Junit详解 作为一名java开发者,相信你或多或少的接触过单元测试,对于测试来讲它是一门能够区分专业开发人员与业余开发人员的重要学科,这篇文章将对java中最常见的一个单元测试框架junit进行一个梳理和讲解。如果你之前没接触过,那么就通过这篇文章进行一个学习。如果你是一个测试老手,我也希望这篇文章能够加深你的印象。