1

这个对象池会导致多线程的可见性问题吗?我特别想知道这种执行顺序:

  • 线程 A - 获得对象()
  • 线程 A - 修改对象(假设为 visibleState = 42)
  • 线程 A - releaseObject()
  • 线程B-obtainObject()(获取A刚刚释放的对象)
  • 线程 A - 做一些不相关的事情或死亡
  • 线程 B - 修改对象(假设为 visibleState = 1)
  • 线程 B - 打印对象 visibleState
  • 线程 B - releaseObject()

在B 修改状态本身之后,来自线程 A 的修改是否可能对线程 B 可见?(我知道它在实践中不会发生,但我无法弄清楚 JLS/Javadoc 是否以及如何保证这一点)。

这是代码,精简后仅显示要领。我省略了泛化和创建对象的工厂。

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

public class ObjectPool {

/** Maximum number of objects to be kept in pool */
int maxPoolSize = 10;

/** First object in pool (LIFO queue) */
final AtomicReference<PoolableObject> firstObject = new AtomicReference<PoolableObject>();

/** How many objects are currently in the pool */
final AtomicInteger poolSize = new AtomicInteger();

/** Gets an object from the pool. If no object is available
 * from the pool, a new object is created and returned */
public PoolableObject obtainObject() {
    while (true) {
        PoolableObject object = firstObject.get();
        if (object == null)
            break;
        if (firstObject.compareAndSet(object, object.next)) {
            poolSize.decrementAndGet();
            return object;
        }
    }
    // no more objects in pool, create a new object
    return new PoolableObject();
}

/** Returns an object to the pool. */
public void releaseObject(final PoolableObject object) {
    while (true) {
        if (poolSize.get() >= maxPoolSize)
            break;
        final PoolableObject first = firstObject.get();
        object.next = first;
        if (firstObject.compareAndSet(first, object)) {
            poolSize.incrementAndGet();
            break;
        }
    }
}

}

池管理的对象应该继承自这个类:

public class PoolableObject {

/** Links objects in pool in single linked list. */
PoolableObject next;

public int visibleState;

}
4

1 回答 1

0

就可见性而言,具有与变量AtomicReference相同的内存屏障属性。volatile

在这些属性中,线程在写入 volatile 变量之前的所有操作“发生在”写入之前。或者,换句话说,如果源代码显示在 volatile 写入之前发生的操作,则 JITC 无法重新排序该操作以在 volatile 写入之后发生。因此,问题中引用的场景不会有问题;在释放之前对对象所做的更改将对随后捕获该对象的其他线程可见。

但是,我并没有完全遵循这个池的工作方式,并且可能存在其他问题。特别是,我不相信 和 之间缺乏原子性firstObjectpoolSize安全的。线程肯定可以看到这些变量处于不一致的状态,因为它们不是synchronized;我不知道这是否重要。

于 2012-04-23T17:57:08.420 回答