0

我有一段代码来创建一个对象并增加创建对象的数量。创建对象并增加计数的代码由 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 编译器优化的代码?

谢谢你。

4

1 回答 1

3

我不确定我是否完全理解这个问题,但可以肯定的是你的代码中有一个竞争条件,因为你的代码基本上是

if (count < max) {
    count++;

如果两个线程首先并行检查是否已达到最大值,然后并行地增加计数,那么即使您只剩下一个插槽,最大值当然也会执行两次:

  • 线程A,检查值,值=9,进入if块
  • 线程B,检查值,值=9,进入if块
  • 线程 A,增量,值 = 10
  • 线程 B,增量,值 = 11

当增量位于位置 B 而不是位置 A 时,我并不感到惊讶,因为在更长的时间范围内计数仍未增加,因此另一个线程可能会进入 if 块。为了更清楚,在位置 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 的增量可能会发生相同的错误。您很幸运没有看到它发生。

于 2013-07-14T18:12:08.993 回答