在做性能测试的过程中,我写了两个虚拟类ThreadLimitTimeCount
和ThreadLimitTimesCount
做框架,通过对线程的标记来完成超时请求的记录。旧方法如下:
@Override protected void after() { requestMark.addAll(marks); marks = new ArrayList<>(); GCThread.stop(); synchronized (this.getClass()) { if (countDownLatch.getCount() == 0 && requestMark.size() != 0) { Save.saveStringList(requestMark, MARK_Path.replace(LONG_Path, EMPTY) + Time.getDate().replace(SPACE_1, CONNECTOR)); requestMark = new Vector<>(); } } }
其中我用了synchronized
关键字同步,但是在匿名类的单元测试中出现一个BUG,匿名类中没有实现clone()
方法,也不能直接使用深拷贝方法,导致无法直接复制对象,所以我创建了多个功能相同的匿名线程类。问题来了,在代码执行过程中,偶然会出现记录markrequest
的文档中出现空内容的形式。
我查询了一些资料,感觉问题出现在synchronized (this.getClass())
这个问题了,因为我打印this.getClass()
给我的是当前测试类的类名,感觉原因就是匿名类的问题,匿名类相当于多个实现类,synchronized (this.getClass())
无法保证多各类对象同时访问这个方法的线程安全。最终,我选择了另外一种方式,就是单独写一个线程安全的save()
方法,这样就可以保证所有访问保存方法的线程的安全,将清空记录列表的功能也放在了这个线程安全的方法里了。
/** * 同步save数据,用于匿名类多线程保存测试数据 * * @param data * @param name */ public static void saveStringListSync(Collection<String> data, String name) { synchronized (Save.class) { if (data.isEmpty()) return; saveStringList(data, name); } }
原来虚拟类的方法就变成了如下的样子:
if (countDownLatch.getCount() == 0 && requestMark.size() != 0) { Save.saveStringListSync(requestMark, MARK_Path.replace(LONG_Path, EMPTY) + Time.getDate().replace(SPACE_1, CONNECTOR)); }