Home > Back-end >  Why the Semaphore implementation uses CAS (U.compareAndSetInt) instead of wait/notify?
Why the Semaphore implementation uses CAS (U.compareAndSetInt) instead of wait/notify?

Time:08-20

I've decided to implement some clasess from the concurrency package from scratch and implemented Semaphore with wait/notify. It seems very easy and intuitive to do so. When I checked the build in implementation, I saw they complicated it all with CAS (Compare And Swap) technique. They did the same for the ReentranceLock implementation.

Why they decided to do it that way? Is it because of performance? Maybe I should also avoid wait/notify and use CAS in my applications.

public class SemaphoreX {
    private int permits;

    SemaphoreX(int permits){
        this.permits = permits;
    }

    public synchronized void acquire() throws InterruptedException{
        while(permits == 0){
            wait();
        }
        permits--;
    }

    public synchronized void release(){
        permits  ;
        notify();
    }
}

CodePudding user response:

You should read the javadocs for AbstractQueuedSynchronizer.

I can't tell you with 100% certainty whether this is about performance. But it is definitely not all about performance.

You will have noticed that the FairSync and UnfairSync classes used by Semaphore are based on AbstractQueuedSynchronizer. If you look at the API, you will see that it provides richer functionality than you get with Java primitive locks and wait / notify. In particular, you will see that it supports fair (FIFO) queuing for threads waiting for events. The Object wait/notify mechanisms don't provide any guaranteed of fairness.

Fair queuing is a requirement for a Semaphore created with fair set to true.

Maybe I should also avoid wait/notify and use CAS in my applications.

Possibly. It depends on what your goals are.

But if your primary goal is performance, then I would recommend NOT trying to re-implement java.util.concurrent... classes. Just use the existing classes as they are.

And if one of your goals is get good performance, you cannot be afraid of using complicated techniques to implement the concurrency primitives. Or of doing your own performance analysis of different approaches and your own performance measurement.

  • Related