Взято из курса Java Multithreading, Concurrency & Performance Optimization

Conceptually, a semaphore maintains a set of permits. Each acquire() blocks if necessary until a permit is available, and then takes it. Each release() adds a permit, potentially releasing a blocking acquirer.

class Semaphore(int permits)
Semaphore full = new Semaphore(0);
Semaphore empty = new Semaphore(1);
Item item = null;
 
Producer:
 
while(true) {
    empty.esquire();
    item = getItem();
    full.release();
}
 
Consumer:
 
while(true) {
    full.esquire();
    consume(item)
    empty.release();
}

javasnippetpatternconcurrency