2012-04-23 4 views
1

このオブジェクトプールは、複数のスレッドで可視性の問題を引き起こす可能性がありますか?私は、具体的実行シーケンスのこのような疑問を抱いています:この同期化されていないオブジェクトプールの実装は良好/安全ですか?

  • スレッドA - obtainObject()
  • スレッドAは - releaseObject()
  • - オブジェクト(visibleState = 42を言うことができます)
  • スレッドAを修正します
  • スレッドB - obtainObject()(単にAでリリースされたオブジェクトを取得します)
  • スレッドA - 関係のない何かをするか、
  • スレッドBを死ぬ - (visibleState = 1を言うことができます)オブジェクトを変更
  • スレッドB - プリントvisibleState
  • スレッドBオブジェクト - releaseObjectを()

スレッドAから修飾はおそらく状態自体を変更したB後に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; 

} 
+0

実際にここにキューはありませんか? –

+0

firstObjectのコメントを参照してくださいか?たぶん私の英語は私にはうまくいかないかもしれませんが、1つのリンクされたリストを合理的に「キュー」と呼ぶことができます。 – Durandal

+1

おそらく、キューのようには使用されていません。サイズ1の['ArrayBlockingQueue'](http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ArrayBlockingQueue.html)は、正しく使用する方がはるかに簡単ですし、 'SynchronousQueue'](http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/SynchronousQueue.html)を参照してください。 –

答えて

0

限り視界が行くように、これらの施設の中でAtomicReference has the same memory barrier properties as a volatile variable.

は、前のスレッドのすべてのアクションということです揮発性変数への書き込みは "起こる前に"書き込みするです。あるいは、別の言い方をすれば、ソースコードが揮発性の書き込みの前に起こっているアクションを示している場合、そのアクションは、JITCが揮発性書き込みの後に発生するように並べ替えることはできません。したがって、問題に引用されたシナリオは問題ではありません。解放される前に行われたオブジェクトへの変更は、後でそのオブジェクトを取得する他のスレッドから見えます。

しかし、私はこのプールが動作する方法に完全に従わず、他の問題がある可能性があります。特に、私はfirstObjectpoolSizeの間の原子性の欠如が安全であるとは確信していません。スレッドは、​​ではないため、これらの変数が矛盾した状態で確実に認識されます。私はそれが重要かどうかは分かりません。

+0

ああ、私はAtomicReferenceの '揮発性'のバリアプロパティを見逃しました。基本的に、AがAtomicReferenceにアクセスする前に実行したメモリ変更は、AtomicRefへのアクセス後にBに可視であることが保証されています。それは私の質問を完全にクリアします。poolSizeについては、実際のプールされたオブジェクトリストと完全には同期していません。私の目的のために、私は避けられない不正確さを考慮しますが、その唯一の効果は、セットプールのサイズが正確に従わないことであり、それは私を悩ますものではありません。 – Durandal

+1

@Durandal: 'AtomicStampedReference'を使って参照とサイズの両方を格納することで、' firstObject'と 'poolSize'の不一致の可能性を排除できます。 – axtavt

関連する問題