Java 在以下程序中检测和处理竞争条件
我是多线程新手,希望避免在下面的代码中出现争用情况。在release()方法中有一行可用的.add(resource),在remove()方法中有一行可用的.remove(resource)。所以我的问题是如何同步'resource'变量以避免这种竞争条件Java 在以下程序中检测和处理竞争条件,java,multithreading,synchronization,threadpool,race-condition,Java,Multithreading,Synchronization,Threadpool,Race Condition,我是多线程新手,希望避免在下面的代码中出现争用情况。在release()方法中有一行可用的.add(resource),在remove()方法中有一行可用的.remove(resource)。所以我的问题是如何同步'resource'变量以避免这种竞争条件 package threadpool; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentHashMap;
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 );
}
}
包线程池;
导入java.util.concurrent.BlockingQueue;
导入java.util.concurrent.ConcurrentHashMap;
导入java.util.concurrent.ConcurrentMap;
导入java.util.concurrent.CountDownLatch;
导入java.util.concurrent.LinkedBlockingQueue;
导入java.util.concurrent.TimeUnit;
公共类ResourcePoolImpl实现ResourcePool{
private static final String CLOSED\u POOL\u EXCEPTION=“池已关闭,无法获取资源。”;
private static final String RELEASE\u EXCEPTION=“非必需资源,无法释放它。”;
private-volatile boolean-open=false;
private final BlockingQueue available=新的LinkedBlockingQueue();
获取的私有最终ConcurrentMap=新ConcurrentHashMap();
public R acquire()抛出InterruptedException{
如果(!open){抛出新的非法状态异常(CLOSED_POOL_EXCEPTION);}
最终R资源=可用。take();
if(资源!=null){
获取.put(资源,新倒计时锁存器(1));
}
返回资源;
}
公共R acquire(最终长超时,最终时间单位)抛出InterruptedException{
如果(!open){抛出新的非法状态异常(CLOSED_POOL_EXCEPTION);}
最终R资源=可用。轮询(超时,时间单位);
if(资源!=null){
获取.put(资源,新倒计时锁存器(1));
}
返回资源;
}
公共布尔加法(最终R资源)
{
返回可用。添加(资源);
}
public void close()引发InterruptedException{
开=假;
对于(最终倒计时闩锁:aquired.values()){
satch.wait();
}
}
公共空间关闭现在(){
开=假;
}
公共布尔等参元(){
返回打开;
}
公开作废{
开放=真实;
}
公开作废发布(最终R资源)
{
final CountDownLatch-latch=aquired.get(资源);
如果(latch==null){抛出新的IllegalArgumentException(RELEASE_EXCEPTION);}
可用。添加(资源);
倒计时();
}
公共布尔移除(最终R资源)抛出InterruptedException
{
final CountDownLatch-latch=aquired.get(资源);
如果(闩锁!=null){
satch.wait();
}
返回可用。删除(资源);
}
公共布尔removeNow(最终R资源){
返回可用。删除(资源);
}
}
声明
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)
}
然后,您可以使用更简单的非并发集合类,因为在互斥保护区内,不能有任何多线程访问
并发集合只是将它们的访问封装在它们自己的内部互斥锁中——但问题是,正如您在注释中所解释的那样,获取的
和可用的
可能会彼此独立地更新,这是您绝对不希望看到的
因此:通过为所有关键区域访问声明并使用单个互斥来简化代码。您如何知道您有竞态条件?可用的是BlockingQueue,它是一个并发集合,如果两个线程都在使用它,它应该不会有问题。并发集合只保证put/get是“原子的”;竞争条件可能在此代码之外(例如,您可能同时从两个地方修改资源…)。您确定此代码中存在问题吗?了解您认为此池的行为会很有趣。例如,在上面的代码中,如果不同线程同时调用“release”和“remove”方法,则可能会导致资源在被删除后被添加回池中,这就是我想要避免的。对资源池中的所有方法使用互斥方法怎么样?。让他们每个人在一个互斥体上同步他们的关键区域,你就可以省去所有那些线程安全的集合(因为互斥体将保护他们所有人)。这肯定会有帮助…但我在想一个更好的方法,比如不必在所有方法上不必要地使用synchronize..那么你的意思是说在这种情况下根本不应该有竞争条件?是否由这些集合处理?查看java源代码后,您使用的这些集合依赖于[ReentrantLocks],其语义与synchronized()提供的内置锁非常相似。我无法想象会有任何性能差异;如果有,单互斥版本应该更快(1个锁而不是多个锁)。另外,你可以避免比赛条件。。。