用Java测试多线程代码

测试多线程代码是一个艰巨的挑战。 尝试测试并发性时获得的第一个建议是尽可能地在代码中隔离并发问题。 这是一般的设计建议,但在这种情况下甚至更重要。 确保首先正确地对并发构造所包装的逻辑进行单元测试。 否则,您可能会花费很长时间尝试找出一个并发问题,最终发现这是有缺陷的业务逻辑。 picot.png

了解了这些内容之后,您就可以考虑测试并发系统的策略。 GOOS涵盖了您如何做到的。 在这里,您可以找到我将要解释的代码:

首先,让我们看一下被测系统:

public class AtomicBigCounter {private BigInteger count = BigInteger.ZERO;public BigInteger count() {return count;}public void inc() {count = count.add(BigInteger.ONE);}}

如您所见,该类不是线程安全的,因为它通过inc()方法公开了一些状态。 状态不是线程安全的(您可以使用AtomicInteger而不是BigInteger进行修复)。 为了测试该类,我们将包括一个非并行和并行测试。

@Test public void canIncreaseCounter(){...}@Test public void canIncrementCounterFromMultipleThreadsSimultaneously()throws  InterruptedException {MultithreadedStressTester stressTester = new MultithreadedStressTester(25000);stressTester.stress(new Runnable() {public void run() {counter.inc();}});stressTester.shutdown();assertThat("final count", counter.count(),equalTo(BigInteger.valueOf(stressTester.totalActionCount())));}

压力测试仪将使用m个线程执行n个循环的方法。 随着我们的方法递增1,我们应该看到n*m等于counter.count()

有趣的类是MultithreadedStressTester:

public void stress(final Runnable action) throws InterruptedException {spawnThreads(action).await();}private CountDownLatch spawnThreads(final Runnable action) {final CountDownLatch finished = new CountDownLatch(threadCount);for (int i = 0; i < threadCount; i++) {executor.execute(new Runnable() {public void run() {try {repeat(action);}finally {finished.countDown();}}});}return finished;}private void repeat(Runnable action) {for (int i = 0; i < iterationCount; i++) {action.run();}}

如果执行该测试,您将收到不同的结果,有时甚至会通过! 那是因为该测试不是确定性的,所以我们无法确保线程在每次执行中如何交错。 如果我们希望尽可能确保此测试找到可能的错误,则应增加线程和迭代的数量,但要权衡时间。

您可以使用Weaver使用更具确定性的方法。 为了理解它是如何工作的,让我们用一个例子来说明它。 假设我们有一个内存中而不是线程安全的存储:

private final Map<Level, Scores> scoresByLevel;

我们有一些服务可以访问包装该存储库的存储库:

1 Optional<Scores> scoresFromStore = scoreRepo.findBy(score.level());2       if(scoresFromStore.isPresent()) {3          scoreRepo.update(score.level(), score);4       } else {5          scoreRepo.save(score.level(), new Scores().add(score));6       }

该服务位于服务器中,是一个单例,每个请求都会生成一个线程,因此我们希望自动执行该部分。 我们可以使用压力测试非确定性方法,也可以使用Weaver。 如果我们对这个问题进行深入思考,我们就会意识到我们要测试以下各项的每个组合(例如,线程1在x时刻执行第1行,线程2在x时刻执行第1行,将是-> T1 / 1: T2 / 1)

  • T1 / 1:T2 / 1
  • T1 / 1:T2 / 2
  • T1 / 1:T2 / 3
  • …。
  • T1 / 2:T2 / 1
  • T1 / 2:T2 / 2
  • T1 / 2:T2 / 3
  • …。

例如,如果T1 / 5和T2 / 2尚未保存,而T2已经从商店中获得了空分,那么我们将遇到问题。 这意味着T1将得分保存在一个级别中,然后T2将这样做,从而破坏了逻辑。 这正是Weaver所做的,它获取一个方法并使用两个线程执行上述组合。

如果我删除了准备代码(用@ThreadedBefore注释),则测试代码将如下所示:

@ThreadedMainpublic void mainThread() {scoreService.save(LEVEL_ID, SCORE_VALUE, aUser);}@ThreadedSecondarypublic void secondThread() {scoreService.save(LEVEL_ID, ANOTHER_SCORE_VALUE, aUser);}@ThreadedAfterpublic void after() {Optional<Scores> scores = scoreRepo.findBy(aLevel());assertThat(scores.isPresent()).isTrue();assertThat(scores.get().contains(aScoreWith(aUser))).isTrue();assertThat(scores.get().contains(aDifferentScoreWith(aUser))).isTrue();}@Testpublic void testThreading() {new AnnotatedTestRunner().runTests(this.getClass(), ScoreService.class);}

由于确定性,该测试将始终失败。 如您所见,测试并发性非常困难,这就是为什么我支持现代框架的原因,这些框架试图将麻烦隐藏在平台中或通过不可变数据解决问题。

  • 您可以在此处了解更多信息。

翻译自: https://www.javacodegeeks.com/2015/12/testing-multithreaded-code-java.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/356093.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

php pdo mysql query_PHP+MYSQL中使用PDO的query方法

一 代码class"php">PDO连接MySQL数据库IDPDO数据库时间$dbmsmysql; //数据库类型 ,对于开发者来说&#xff0c;使用不同的数据库&#xff0c;只要改这个&#xff0c;不用记住那么多的函数$hostlocalhost; //数据库主机名$dbNamedb_database15; //使用的数据库$use…

pat 团体赛练习题集 L2-008. 最长对称子串

对给定的字符串&#xff0c;本题要求你输出最长对称子串的长度。例如&#xff0c;给定"Is PAT&TAP symmetric?"&#xff0c;最长对称子串为"s PAT&TAP s"&#xff0c;于是你应该输出11。 输入格式&#xff1a; 输入在一行中给出长度不超过1000的…

在Apache Camel中使用Spring数据

Spring Data通过创建智能的DAO节省了很多时间&#xff0c;您基本上不需要编写任何代码就可以免费获得DAO。 它基本上遵循Eric Evans的DDD书中的“ 存储库模式 ” &#xff0c;并将实体视为集合。 它有一个很好的约定&#xff0c;允许您为复杂查询指定条件&#xff0c;甚至可以将…

python协程池操作mysql_python_协程方式操作数据库

#!/usr/bin/python3# -*- coding: utf-8 -*-import requestsimport geventimport pymysqlfrom gevent import monkey# 堵塞标记monkey.patch_all()class SqlSave(object):"""协程方式写入数据库"""def __init__(self):SQL_DBA {‘host‘: ‘loc…

bootstrap在ie8下,兼容媒体查询

最近使用bootstrap做网站的时候发现&#xff0c;在ie8下的媒体查询一直失效&#xff1a; 后来解决了&#xff0c;做如下记录&#xff1a; 1、必须运行在服务器下 2、hack 条件语法&#xff0c;如下&#xff1a; <!--[if lte ie 9]><script src"js/html5shiv.min.…

java 冒号 正则表达式_Java正则表达式问号冒号的使用

在Java和Javascript中正则表达式字符串前面加上?:表示非捕获型匹配&#xff0c;否则就是捕获型匹配。捕获型括号会将匹配到的内容捕获到一些变量里&#xff0c;这些变量按照捕获型括号的左括号为顺序从1开始编号。为了避免括号太多使编号混乱&#xff0c;也为了避免无用的捕获…

Hibernate中的一对多XML映射

一对多关系指出一个实体的单个实例与另一个实体的多个实例相关联。 换句话说&#xff0c;一个表中的每个记录与另一个表中的多个记录相关联。 让我们看看如何通过XML映射文件在Hibernate中定义这种关系。 1.实体关系图 假设我们已经在数据库中创建了学生表和部门表&#xff0…

java resize_OpenCV3 Java图像放大缩小 修改图像大小(Imgproc.resize)

Imgproc.resize()方法参数&#xff1a;src&#xff1a;输入&#xff0c;原图像&#xff0c;即待改变大小的图像&#xff1b;dst&#xff1a;输出&#xff0c;改变大小之后的图像&#xff0c;这个图像和原图像具有相同的内容&#xff0c;只是大小和原图像不一样而已&#xff1b;…

mongodb中Gson和java##Bean对象转化类

此类使用感觉比较繁琐, 每个字段加注解才可以使用, 不如mongoTemplate使用方便, 但如果使用mongo客户端的话, 还是比手动拼接快一点, 所以贴在这儿 package com.iwhere.util;import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java…

java中sql查询语句_JAVA中用 SQL语句操作小结

1、添加记录(INSERT)使用SQL语句的INSERT命令可以向数据库中插入记录&#xff0c;INSERT命令的基本形式为&#xff1a;INSERT INTO 表名 [(字段名1,字段名2…)] VALUES (值1,值2,…)若在输入记录时&#xff0c;每个字段均有内容&#xff0c;可省略表名后的字段名。该SQL语句用于…

专题:二分图匹配

挖坑转载于:https://www.cnblogs.com/bestwzh/p/6487477.html

camel eip_Apache Camel教程– EIP,路由,组件,测试和其他概念的简介

camel eip公司之间的数据交换增加了很多。 必须集成的应用程序数量也增加了。 这些接口使用不同的技术&#xff0c;协议和数据格式。 但是&#xff0c;这些应用程序的集成应以标准化的方式建模&#xff0c;有效实现并由自动测试支持。 企业集成模式&#xff08;EIP&#xff09;…

java map 不存在的key_java – HashMap表示即使它确实存在,Key也不存在

我遇到了一个有趣的问题,我很确定是HashMap的错.考虑以下调试代码(AMap是HashMap,key是传递给此方法的值)System.out.println("getBValues - Given: " key);System.out.println("getBValues - Contains Key: " AMap.containsKey(key));System.out.printl…

XML 解析器

XML Parser 所有现代浏览器都有内建的 XML 解析器。 XML 解析器把 XML 文档转换为 XML DOM 对象 - 可通过 JavaScript 操作的对象。 解析 XML 文档 下面的代码片段把 XML 文档解析到 XML DOM 对象中&#xff1a; if (window.XMLHttpRequest){// code for IE7, Firefox, Chrome,…

JavaOne和OOW 2015总结

大家好&#xff01; 终于&#xff0c;我回来了一个很棒的JavaOne和OOW2015。在这篇文章中&#xff0c;我想分享我的经验&#xff0c;一些照片和我参加的演讲的摘要。 会议前 我于2015年6月24日星期六乘Copa航空公司CLO-PTY-SFO飞往旧金山。 从哥伦比亚出发&#xff08;大约8小…

java mongodb dbref_Spring DATA MongoDB @DBref查询,or和and联合查询

DBref文档关联&#xff0c;在按该类型查询的时候&#xff0c;在字段名后加上关联表的字段名即可&#xff0c;如&#xff1a;Criteria.where("bloggroup.$id")&#xff0c;$id代表关联表的oid字段。or和and联合查询比如查询 (A 1 and b 2 )or (A 3 and b 4)&#x…

【hdoj_2152】Fruit(母函数)

题目&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid2152 本题采用母函数模板求解&#xff0c;母函数模板如下&#xff1a; http://blog.csdn.net/ten_sory/article/details/59483762 本题中的价值v[i]均为1&#xff0c;s[i]A[i],e[i]B[i]&#xff0c;套用上述模板&am…

java holdslock_一种检测Java并发程序代码分支路径lock是否遗漏的方法

开发java程序中&#xff0c;程序员往往会用synchronized lock 进行临界资源保护和线程同步&#xff1b;android平台上&#xff0c;提供了一些技巧来减少锁被错误使用&#xff1a;使用Locked后缀作为函数名字&#xff1a;Locked函数被调用&#xff0c;需调用方(或者更上层调用方…

Marin说PCB之 PCB封装和原理图封装的藕断丝连--续集(2)

最近天气越来越冷了&#xff0c;小编我在上海漂泊的十多年了&#xff0c;感觉今年似乎是最冷的一年啊。家里的秋裤都不管用了&#xff0c;要换成大棉裤和军大衣啊。而且现在羽绒服大部分都很贵&#xff0c;动不动上千元了&#xff0c;都赶得上小编我几个月的私房钱了都&#xf…

调整线程池的重要性

无论您是否知道&#xff0c;您的Java Web应用程序很可能都使用线程池来处理传入的请求。 这是许多人忽略的实现细节&#xff0c;但是迟早您需要了解如何使用该池以及如何为您的应用程序正确调整池。 本文旨在说明线程模型&#xff0c;什么是线程池以及正确配置线程池所需执行的…