3

マルチスレッドは初めてで、以下のコードで発生している競合状態を回避したいと考えています。release() メソッドには available.add(resource) という行があり、remove() メソッドには available.remove(resource) という行があります。私の質問は、この競合状態を回避するために「リソース」変数を​​同期するにはどうすればよいですか?

    package threadpool;
    import java.util.concurrent.BlockingQueue;
    import java.util.concurrent.ConcurrentHashMap;
    import java.util.concurrent.ConcurrentMap;
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.LinkedBlockingQueue;
    import java.util.concurrent.TimeUnit;

    public class ResourcePoolImpl<R> implements ResourcePool<R> {

    private static final String CLOSED_POOL_EXCEPTION = "Pool is closed,cannot aquire resource.";

    private static final String  RELEASE_EXCEPTION = "Unaquired resource, cannot release it.";

    private volatile boolean open = false;

    private final BlockingQueue<R> available = new LinkedBlockingQueue<R>();

    private final ConcurrentMap<R, CountDownLatch> aquired = new ConcurrentHashMap<R,  CountDownLatch>();

    public R acquire() throws InterruptedException {
    if ( !open ) { throw new IllegalStateException( CLOSED_POOL_EXCEPTION ); }
    final R resource = available.take();
    if ( resource != null ) {
        aquired.put( resource, new CountDownLatch( 1 ) );
    }
    return resource;
    }


   public R acquire( final long timeout, final TimeUnit timeUnit ) throws InterruptedException {
    if ( !open ) { throw new IllegalStateException( CLOSED_POOL_EXCEPTION ); }

    final R resource = available.poll( timeout, timeUnit );
    if ( resource != null ) {
        aquired.put( resource, new CountDownLatch( 1 ) );
    }
    return resource;
    }


    public boolean add( final R resource ) 
    {
    return available.add( resource );
    } 

    public void close() throws InterruptedException {
    open = false;
    for ( final CountDownLatch latch : aquired.values() ) {
        latch.await();
    }
    }

    public void closeNow() {
    open = false;
    }

    public boolean isOpen() {
    return open;
    }

    public void open() {
    open = true;
    }

    public void release( final R resource ) 
    {
    final CountDownLatch latch = aquired.get( resource );
    if ( latch == null ) { throw new IllegalArgumentException( RELEASE_EXCEPTION ); }
    available.add( resource );
    latch.countDown();
    }

    public boolean remove( final R resource ) throws InterruptedException 
    {   

    final CountDownLatch latch = aquired.get( resource );
    if ( latch != null ) {
        latch.await();
    }
    return available.remove( resource );
    }


    public boolean removeNow( final R resource ) {
    return available.remove( resource );
    }

 }
4

1 に答える 1

2

宣言する

final Object mutex = new Object();

共有コレクションで読み取り/書き込み操作を行うすべてのメソッドは、操作を行う前にミューテックスを取得するか、共有データに基づいて決定を行い、同期ブロック内で実行されます。

synchronized (mutex) {
     // .. guaranteed single-threaded access here
     //   (for instance, contents of aquire() or release(); 
     //      also add() or any other collection access)
}

次に、ミューテックスで保護された領域内ではマルチスレッド アクセスができないため、より単純な非並行コレクション クラスを使用できます。

並行コレクションは、アクセスを独自の内部相互排除ロック内にラップするだけですが、コメントで説明しているように、問題はそれaquiredでありavailable、互いに独立して更新される可能性があることです。これは絶対に望ましくありません。

したがって、すべての重要な領域へのアクセスに対して単一のミューテックスを宣言して使用することにより、コードを簡素化します。

于 2013-01-09T14:20:48.903 に答える