Semaphores should not be used in the place of synchronized because semaphores does not hold exclusive mutual lock even if it is initialized to one, like synchronized on some object. It is true that the semaphore initialized to one, allows only one thread at a time to access the object, which holds the permit. But the thread which holds the permit does not own it, any other thread could release that permit and acquire the permit. So, two threads could get access to the same object at the same time, and if both threads manipulates that object, there will be multi-threading issues like lost update, stale read etc.
In your example of having 2 threads, one increasing and one decreasing the same variable. mutual exclusion is sufficient and volatile declaration is not needed. here I assume mutual exclusion is achieved via synchronized and not by semaphores.
volatile is less strict than synchronized, you may want to use volatile when the operations performed are atomic (read or write). volatile should not be used when the performing read-update-write operation.