这种不同步的对象池实现是否良好/安全?

时间:2012-04-23 17:38:31

标签: java synchronization lock-free pooling

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

  • 线程A - obtainObject()
  • 线程A - 修改对象(比如visibleState = 42)
  • 线程A - releaseObject()
  • 线程B - obtainObject()(获取刚刚由A发布的对象)
  • 线程A - 做一些无关或死亡的事情
  • 线程B - 修改对象(比如说visibleState = 1)
  • 主题B - 打印对象visibleState
  • 主题B - releaseObject()

在 B修改了状态本身后,线程B 可能会对线程A的修改可见吗? (我知道它在实践中不会发生,但我无法弄清楚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;

}

1 个答案:

答案 0 :(得分:0)

就知名度而言,AtomicReference has the same memory barrier properties as a volatile variable.

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

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