白盒测试中如何实现真正意义上并发测试(Java)
2015-08-04 10:49
507 查看
在这个话题开始之前,首先我们来弄清楚为什么要做并发测试?
一般并发测试,是指模拟并发访问,测试多用户并发访问同一个应用、模块、数据时是否产生隐藏的并发问题,如内存泄漏、线程锁、资源争用问题。
站在性能测试的角度,并发测试不是为了获得性能指标,而是为了发现并发引起的问题。
那么并发对应的技术实现到底是怎样的呢?
简单地说,并发是指多个进程或线程在某一时刻同时处理指定的操作,有点类似于性能测试中集合点的概念,讲究同时性。
普及到这里,接下来讨论技术实现:
最近在项目里面发现一些开发人员做动态测试模拟500并发时,实现代码如下:
代码片段1:
因为涉及一些共享对象的使用,避免多线程乱序现象,我建议加上同步锁,后来开发人员改写了代码,实现如下:
代码片段2:
其实上述这种方式在CPU层面采用的是FIFO策略(先进先出),线程是依次拿到锁资源进行处理的,无法达到同时性,所以我决定自己来做白盒测试,使用下面2种方式来实现:CyclicBarrier 和 CountDownLatch .
代码片段3:
上面每个线程都共享了一个计数器,减1后调用await()方法挂起,直到count减为0时,才一起继续执行;
代码片段4:
所有线程创建完毕后调用await()方法挂起,直至所有线程都到达barrier状态再同时执行;
声明:在这里,CyclicBarrier的barrier状态是可重用的,而CountDownLatch是不可重用的,个人还是推荐CyclicBarrier,因为性能上损耗较小些!
今天就总结到这了~~
一般并发测试,是指模拟并发访问,测试多用户并发访问同一个应用、模块、数据时是否产生隐藏的并发问题,如内存泄漏、线程锁、资源争用问题。
站在性能测试的角度,并发测试不是为了获得性能指标,而是为了发现并发引起的问题。
那么并发对应的技术实现到底是怎样的呢?
简单地说,并发是指多个进程或线程在某一时刻同时处理指定的操作,有点类似于性能测试中集合点的概念,讲究同时性。
普及到这里,接下来讨论技术实现:
最近在项目里面发现一些开发人员做动态测试模拟500并发时,实现代码如下:
代码片段1:
public static void main(String[] args) { // TODO Auto-generated method stub for(int i=0;i<500;i++){ new MyThread().run(); } } static class MyThread implements Runnable{ @Override public void run() { // TODO Auto-generated method stub // 定义每个线程负责的业务逻辑实现 } }
因为涉及一些共享对象的使用,避免多线程乱序现象,我建议加上同步锁,后来开发人员改写了代码,实现如下:
代码片段2:
public static void main(String[] args) { // TODO Auto-generated method stub // 定义线程池,模拟500并发请求 ThreadPoolExecutor executor = new ThreadPoolExecutor(500, 500, 1000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(500), new ThreadPoolExecutor.DiscardOldestPolicy()); for(int i=0;i<500;i++){ executor.execute(new MyThread()); } executor.shutdown(); } static class MyThread implements Runnable{ @Override public void run() { // TODO Auto-generated method stub // 定义每个线程负责的业务逻辑实现 synchronized (this) { } } }
其实上述这种方式在CPU层面采用的是FIFO策略(先进先出),线程是依次拿到锁资源进行处理的,无法达到同时性,所以我决定自己来做白盒测试,使用下面2种方式来实现:CyclicBarrier 和 CountDownLatch .
代码片段3:
public static void main(String[] args) { // TODO Auto-generated method stub CountDownLatch cdl = new CountDownLatch(500); for (int i = 0; i < 500; i++) { new MyThread(cdl).run(); } try { cdl.await();//调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } static class MyThread implements Runnable { private CountDownLatch cdl; public MyThread(CountDownLatch cdl) { this.cdl = cdl; } @Override public void run() { // TODO Auto-generated method stub cdl.countDown();//将count值减1 // 定义每个线程负责的业务逻辑实现 } }
上面每个线程都共享了一个计数器,减1后调用await()方法挂起,直到count减为0时,才一起继续执行;
代码片段4:
public static void main(String[] args) { // TODO Auto-generated method stub CyclicBarrier cb = new CyclicBarrier(500); ExecutorService es = Executors.newFixedThreadPool(500); for (int i = 0; i < 500; i++) { es.execute(new MyThread(cb)); } es.shutdown(); } static class MyThread implements Runnable { private CyclicBarrier cb; public MyThread(CyclicBarrier cb) { this.cb = cb; } @Override public void run() { // TODO Auto-generated method stub try { // 等待所有任务准备就绪 cb.await(); // 定义每个线程负责的业务逻辑实现 } catch (Exception e) { e.printStackTrace(); } } }
所有线程创建完毕后调用await()方法挂起,直至所有线程都到达barrier状态再同时执行;
声明:在这里,CyclicBarrier的barrier状态是可重用的,而CountDownLatch是不可重用的,个人还是推荐CyclicBarrier,因为性能上损耗较小些!
今天就总结到这了~~
相关文章推荐
- Java线程调度器ScheduledThreadPoolExecutor 分析
- 如何把浏览器上显示的页面数据 转换成 java字符串---java.net.URL
- Eclipse+jdk环境搭建
- eclipse保存内容,弹出svn错误框:updating change sets for svnStatusSubscriber
- 『Spring.NET+NHibernate+泛型』框架搭建之WebUI(五)★
- Java多线程——<二>将任务交给线程,线程声明及启动
- javabean是什么?
- struts1
- 不能创建src/main/java 源文件夹的问题
- 代码生成器:Java自动生成service,serviceImpl及action
- struts2拦截器interceptor的三种配置方法
- Spring 配置log4j和简单介绍Log4J的使用
- java内存机制说明(简单明了)
- spring中context:property-placeholder/元素
- java中File的使用
- MyEclipse10 SVN(subclipse) 笔记
- java 不区分KEY大小写的MAP
- Spring JdbcTemplate 查询出的Map,是如何产生大小写忽略的Key的?
- JAVA中finally和return的故事
- Java反射机制