我有一段代码来创建一个对象并增加创建对象的数量。创建对象和增加计数的代码,由if条件检查计数是否已达到MAX数量的对象。当运行具有多线程的代码时,if条件可能被破坏(即没有效果)由行的位置确定增加计数。这可能是由Java编译器优化引起的吗?以下是代码片段:
private BlockingQueue<WeakReference<ItemType>> items;
private final ReferenceQueue<ItemType> referenceQueue = new ReferenceQueue<ItemType>();
private final int maxSize = 10;
private final AtomicInteger numberOfCreatedObj = new AtomicInteger(0);
protected ItemType create(boolean addToCache) {
ItemType item = null;
try {
if (!hasCreatedMaxObjects()) {
// we have not reached maxSize yet.
item = getFactory().create();
// this position makes the MAX objects checking working
// Position A:
increaseCreatedObjectCount();
LOG.debug("Created new item [" + item.getId() + "]");
if (addToCache) {
LOG.debug("Add to cache the new item [" + item.getId() + "]");
addCreated(item);
}
// This position makes the MAX objects checking failed
// Position B;
//increaseCreatedObjectCount();
} else {
LOG.warn("Already reached MAX created objects " + numberOfCreatedObj.get());
}
} catch (Exception e) {
LOG.error("Error in creating a new object", e);
}
return item;
}
protected boolean hasCreatedMaxObjects() {
return getNumberOfCreatedObj().compareAndSet(getMaxSize(), getMaxSize());
}
protected void increaseCreatedObjectCount() {
getNumberOfCreatedObj().incrementAndGet();
}
protected void addCreated(ItemType item) {
items.offer(new WeakReference<ItemType>(item, referenceQueue));
}
我用30个线程运行我的测试。获取创建的对象后,每个线程都会休眠100毫秒。当在位置A调用increaseCreatedObjectCount()时,代码工作正常并且创建了10个(MAX)对象。当在位置B调用increaseCreatedObjectCount()时,创建了30个对象,这等于正在运行的线程数。
我如何查看Java编译器优化代码?
谢谢。
答案 0 :(得分:3)
我不确定我是否完全理解了这个问题,但是你的代码确实存在竞争条件,因为你的代码基本上是
if (count < max) {
count++;
如果两个线程首先同时检查是否已达到最大值,然后并行增加计数,那么即使只剩下一个插槽,最大值也会实现两次:
当增量位于位置B而不是位置A时,我并不感到惊讶,因为有一个更长的时间范围,在此期间计数仍然没有增加,而另一个线程可能因此进入如果阻止。为了更清楚,位置B处增量的代码与
相当if (count < max) {
sleep(ENOUGH_TIME_FOR_ANOTHER_THREAD_TO_STILL_SEE_THE_NON_INCREMENTED_VALUE)
count++;
编译器优化因此与问题无关。问题是缺乏同步,或缺乏正确使用AtomicInteger。 if块应为
if (numberOfCreatedObj.getAndIncrement() < maxSize) {
...
}
另外,请注意,即使您的测试显示在增量处于位置A时它按预期工作,这只是一个意外。在位置A处增加可能会发生同样的错误。你很幸运,没有看到它发生。