我正在研究并发性,我想了解为什么对以下两种操作之一执行先读后写操作: CopyOnWriteArrayList
或者 synchronizedList()
在多线程场景中导致不确定性行为。
代码如下所示:
public class LoadBalancer {
private static final Integer MAX_PROVIDERS_SIZE = 10;
private final List<String> registeredProviders;
private LoadBalancer(List<String> initialProviders) {
if (!(initialProviders.size() == new HashSet<>(initialProviders).size())) {
throw new ProviderAlreadyExists();
}
this.registeredProviders = Collections.synchronizedList(initialProviders);
}
public static LoadBalancer of(List<String> registeredProviders) {
return new LoadBalancer(registeredProviders);
}
public LoadBalancer registerProvider(String provider) {
if (registeredProviders.size() >= MAX_PROVIDERS_SIZE) {
throw new ProvidersLengthExceeded();
} else {
registeredProviders.stream().filter(p -> p.equals(provider))
.findFirst()
.ifPresent(p -> {
throw new ProviderAlreadyExists();
});
registeredProviders.add(provider);
System.out.println("SIZE" + registeredProviders.size());
}
return this;
}
public List<String> getRegisteredProviders() {
return registeredProviders;
}
}
public class ProvidersLengthExceeded extends RuntimeException{
public ProvidersLengthExceeded() {
super("The maximum providers size is 10.");
}
}
public class ProviderAlreadyExists extends RuntimeException{
public ProviderAlreadyExists() {
super("The provider already exists.");
}
}
这就是测试:
@Test
public void concurrencyCheck() throws InterruptedException {
List<String> testProviders = IntStream.rangeClosed(0, 8).mapToObj(index -> index + "")
.collect(Collectors.toList());
LoadBalancer lb = LoadBalancer.of(testProviders);
ExecutorService service = Executors.newFixedThreadPool(10);
IntStream.range(0, 100).forEach(i -> service.submit(() -> {
lb.registerProvider(UUID.randomUUID().toString());
}));
Thread.sleep(10_000);
System.out.println(lb.getRegisteredProviders().size());
}
}
我期望的行为是我不能添加超过 MAX_PROVIDERS_SIZE
列表中的项目。通过上面的代码,我得到以下输出:
SIZE11
SIZE10
SIZE13
SIZE12
13
如果在添加之前对过滤部分进行注解,则得到正确的输出:
SIZE10
10
为什么会这样?
暂无答案!
目前还没有任何答案,快来回答吧!