我正在尝试将装饰器编写到现有的类中,如果没有足够的可用资源则拒绝该类。以下是完全没有多线程的代码示例版本:
public interface Handler {
boolean handleTask(Task myTask); // returns true if successful, false if failure
}
public interface Task {
int getResources();
// Among other things
}
public BlockingHandler implements Handler {
private int occupied;
private final int limit;
private final Handler backingHandler;
BlockingHandler(Handler backingHandler) {
this.backingHandler = backingHandler;
}
@Override
public boolean handleTask(Task myTask) {
if(myTask.getResources() + occupied > limit) return false;
occupied += myTask.getResources();
return backingHandler.handleTask(myTask);
}
// Don't worry about this part, I'm not doing it this way, I just want the code to make sense
public void notifyResourceRelease(Task finishedTask) {
if(finishedTask.isDone()) occupied -= myTask.getResources();
}
}
问题是,这个handleTask
方法可以在多个线程上调用,我想要非常快(即避免synchronized
)。仅occupied
为volatile
或AtomicInteger
是不够的,因为竞争条件仍有可能,例如:
Thread 1: call handleTask
Thread 1: call atomicOccupied.get()
Thread 2: call handleTask
Thread 1: evaluate if condition
Thread 2: call atomicOccupied.get()
是否可以在不使用synchronized
的情况下执行此操作?例如,是否有一个扩展的AtomicInteger
类具有更强大的compareAndSet
?
答案 0 :(得分:6)
是否可以在不使用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。你需要旋转,因为如果其他线程已经更新了你获得前一个值之间的占用计数,那么你需要调整该值,然后你需要循环并再次获得占用的数量。这是一种典型的模式。
此外,您需要使用AtomicInteger
而不是volatile
,因为您使用的是compareAndSet
。有关更多信息,请参阅此问题:
What is the difference between using a volatile primitive over atomic variables?