1

このオブジェクト プールは、複数のスレッドで可視性の問題を引き起こす可能性がありますか? 私は特に、この種の実行シーケンスについて疑問に思っています:

  • スレッド A - getObject()
  • スレッド A - オブジェクトを変更します (visibleState = 42 としましょう)
  • スレッド A - releaseObject()
  • スレッド B - acquireObject() (A によって解放されたばかりのオブジェクトを取得します)
  • スレッド A - 関係のないことをするか、死ぬ
  • スレッド B - オブジェクトを変更します (visibleState = 1 としましょう)
  • スレッド B - オブジェクトを表示する
  • スレッド 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

これらのプロパティの中には、揮発性変数への書き込み前のスレッドのすべてのアクションが、その書き込みの「前に起こる」というものがあります。別の言い方をすれば、揮発性書き込みの前にアクションが発生していることをソース コードが示している場合、そのアクションは、揮発性書き込みの後に発生するように JITC によって並べ替えることはできません。したがって、質問で引用されているシナリオは問題になりません。オブジェクトが解放される前に加えられた変更は、その後オブジェクトをキャプチャする他のスレッドに表示されます。

ただし、このプールが機能するはずの方法に完全に従っているわけではなく、他の問題がある可能性があります。特に、 と の間のアトミック性の欠如が安全であるfirstObjectとは確信していません。poolSizeスレッドは、これらの変数が一貫性のない状態にあることを確実に確認できsynchronizedます。それが重要かどうかはわかりません。

于 2012-04-23T17:57:08.420 に答える