Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 是否有更好的AtomicInteger比较功能用于竞争条件?_Java_Multithreading_Synchronization_Race Condition - Fatal编程技术网

Java 是否有更好的AtomicInteger比较功能用于竞争条件?

Java 是否有更好的AtomicInteger比较功能用于竞争条件?,java,multithreading,synchronization,race-condition,Java,Multithreading,Synchronization,Race Condition,我试图为一个现有类编写一个decorator,如果没有足够的可用资源,该类将拒绝。下面是一个完全没有多线程的代码示例版本: 公共接口处理程序{ 布尔handleTask(Task myTask);//如果成功则返回true,如果失败则返回false } 公共接口任务{ int getResources(); //除其他外 } 公共阻止处理程序实现处理程序{ 私人住宅; 私人最终整数限制; 私人最终经办人-后台经办人; 阻塞处理器(处理器背面处理器){ this.backingHandler=ba

我试图为一个现有类编写一个decorator,如果没有足够的可用资源,该类将拒绝。下面是一个完全没有多线程的代码示例版本:

公共接口处理程序{
布尔handleTask(Task myTask);//如果成功则返回true,如果失败则返回false
}
公共接口任务{
int getResources();
//除其他外
}
公共阻止处理程序实现处理程序{
私人住宅;
私人最终整数限制;
私人最终经办人-后台经办人;
阻塞处理器(处理器背面处理器){
this.backingHandler=backingHandler;
}
@凌驾
公共布尔HandletTask(任务myTask){
if(myTask.getResources()+已占用>限制)返回false;
占用的+=myTask.getResources();
返回backingHandler.handleTask(myTask);
}
//不要担心这部分,我不是这样做的,我只是想让代码有意义
public void notifyResourceRelease(任务完成任务){
如果(finishedTask.isDone())被占用-=myTask.getResources();
}
}
问题是,这个
handleTask
方法可以在多个线程上调用,我希望非常快(即避免
synchronized
)。仅使
被占用
成为
易失性
原子整数
是不够的,因为竞争条件仍然是可能的,例如:

Thread 1: call handleTask
Thread 1: call atomicOccupied.get()
Thread 2: call handleTask
Thread 1: evaluate if condition
Thread 2: call atomicOccupied.get()
是否可以在不使用
同步的情况下执行此操作?例如,是否有一个扩展的
AtomicInteger
类具有更强大的
compareAndSet

是否可以在不使用synchronized的情况下执行此操作?例如,是否有一个扩展的AtomicInteger类具有更强大的compareAndSet

您应该能够在没有
synchronized
块的情况下完成此操作。不,没有更多扩展的
AtomicInteger

如果我了解您的需求,您可以在
while
循环中执行此操作。比如:

final AtomicInteger occupied = new AtomicInteger();
...
int prev;
int numResources = myTask.getResources();
do {
    prev = occupied.get();
    if (numResources + prev > limit) return false;
} while (!occupied.compareAndSet(prev, prev + numResources));
如果可能,此循环将旋转更新已占用的资源。如果达到限制,它将返回false。您需要旋转,因为如果其他线程在您获得上一个值和您调整该值之间更新了占用的计数,那么您将需要循环并再次获得占用的计数。这是一种典型的模式


另外,您需要在
volatile
上使用
AtomicInteger
,因为您使用的是
compareAndSet
。有关更多信息,请参见此问题:


听起来像是a的工作。为什么不使用ArrayBlockingQueue呢?该类是为此类功能而构建的。我相信这一点已经得到了回答@如果(!semaphore.tryAcquire())抛出新的SomeException(),则可以使用
。它本质上是一个原子整数,所以我会使用它,而不是手动重新实现一个非常类似的逻辑。@Assylas别介意我记错了
信号量的工作方式,我记得
.acquire()
,但不记得
.tryAcquire()
我想到了这一点,但我不确定它是否比
同步快
在大多数情况下,它会比阻塞@durron597快。唯一的例外是,如果有大量线程,并且占用的更新是高度争用的。即使是这样,它也可能优于<代码>同步< /代码>。但是阻塞队列或某些东西可能优于两种。@ DurRAN597认为,<代码>同步< /COD>至少有一个易失性读(<代码> AtomicInteger。获取< /COD>和一个易失性集合<代码> AtomicInteger。设置< /代码>)。这当然会有更高的性能。我想答案是“是的,它是必需的”,但我只想检查一下:
AtomicInteger
仍然是必需的还是将
volatile
足够?使用AtomicInteger并将其声明为最终结果。它包装了一个易失性字段(带有一些CAS/原子指令),但您不必担心它。原语的易变增量不是原子的,原因有很多解释。