我有一个Spring服务,我想测试并发线程的正确性。
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class SerialNumberServiceTest {
@Autowired
private SerialNumberService service;
private final static int NUM_THREADS = 10;
private final static int NUM_ITERATIONS = 100;
@Test
public void testSynchronized(){
ExecutorService executor = Executors.newFixedThreadPool(10);
final Set<String> result = new HashSet<String>();
int size = 0;
for(int i = 0; i < NUM_THREADS; i++){
executor.submit(new Runnable() {
@Override
public void run() {
for (int j = 0; j < NUM_ITERATIONS; j++) {
String code = service.generateSerialNumberByModelCode("LP");
result.add(code);
}
}
});
}
assertEquals(NUM_ITERATIONS * NUM_THREADS, result.size());
}
}
我想断言生成了多少代码,并检查是否有重复的代码。
但是结果集为空。我不知道为什么。
另一方面,如果我尝试更新线程中服务实例的值,那么我还会发现这些值未保存。例如
public void run() {
for (int j = 0; j < NUM_ITERATIONS; j++) {
String code = service.generateSerialNumberByModelCode("LP");
service.incrValue();
result.add(code);
}
}
最后,service.getValue()不变。
有人可以为我解释吗?
最佳答案
此代码有很多错误。
1)您正在使用HashSet
并在多个线程中对其进行更新,但记录为HashSet
不是线程安全的。这会导致意外的行为,或者如果您很幸运的话,会出现ConcurrentModificationException
。将其包装在同步集中。
2)在执行断言之前,您不等待提交的线程完成。使用invokeAll
启动多个线程,或通过在执行程序上执行shutdown
然后在awaitTermination
上等待所有线程完成。有关更好的解释,请参见以下问题:ExecutorService, how to wait for all tasks to finish