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();
}
}
You should read the javadocs for AbstractQueuedSynchronizer
.
Why they decided to do it that way? Is it because of performance?
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 primitive wait / notify mechanisms don't provide any guarantees 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.