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

时间:2014-02-24 14:44:17

标签: java multithreading synchronization race-condition

我正在尝试将装饰器编写到现有的类中,如果没有足够的可用资源则拒绝该类。以下是完全没有多线程的代码示例版本:

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)。仅occupiedvolatileAtomicInteger是不够的,因为竞争条件仍有可能,例如:

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

1 个答案:

答案 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?