java - 在下面的程序中检测和处理竞争条件

标签 java multithreading synchronization threadpool race-condition

我是多线程的新手,想避免以下代码中出现的竞争条件。在 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 );
    }

 }

最佳答案

声明一个

final Object mutex = new Object();

并让所有对共享集合执行读/写操作的方法在执行操作之前获取互斥锁,或根据共享数据做出决策,在同步块(synchronized block)中执行:

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

然后您可以使用更简单的非并发集合类,因为在互斥保护区域内,不能进行任何多线程访问。

并发集合简单地将它们的访问包装在它们自己的内部互斥锁中——但正如您在评论中解释的那样,问题是 aquiredavailable 可能彼此独立更新,这是您绝对不希望的。

因此:通过为所有关键区域访问声明和使用单个互斥锁来简化您的代码。

关于java - 在下面的程序中检测和处理竞争条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14237069/

相关文章:

java - 脚本文件无法创建Java Jar文件

linux - sighandler 和其他线程

java - 术语同步和线程安全是什么意思?

java - 两个线程访问的同步块(synchronized block)

java - 聚合后缺少最后一组

java - 内置(或流行的第 3 方库)在原始类型和相应引用类型 ("wrapper"之间进行映射的方式)?

java - 如何使用 apache poi 从 ppt、pptx 文件中提取除页脚、幻灯片编号之外的文本?

c - Freeswitch 阻塞

java - 如何在 SQLite Java 中设置线程模式

java - 在java中以循环方式运行线程