我有一个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

07-24 09:33