Semaphores have lock semantics.
Semaphores have permits. You can obtain a permit by calling:
semaphore.acquire()
You can release the permit as follows:
semaphore.release()
A semaphore is instantiated with a number of permits:
semaphore = new Semaphore( numberThreads );
If all the permits have been acquired and they are not yet released, the acquire method will block waiting for a permit to be released:
semaphore.acquire()
To get the code for this example:
git clone https://github.com/spotadev/java-examples.git
In both src/main/java and src/test/java navigate to this package:
com.javaspeak.java_examples.concurrency.semaphore
You can run the testng unit test using a testng plugin for your IDE or you can run the main method of:
SemaphoreExampleTest
This example is about using a Semaphore to control access to a Blocking Thread Pool. The Thread Pool gives you a thread in the executableRunnable() method if there is an available one else it blocks waiting for one to come available.
package com.javaspeak.java_examples.concurrency.semaphore;
/**
* @author John Dickerson - 23 Dec 2022
*/
public interface BlockingThreadPool {
void executeRunnable( Runnable runnable );
int numberFreeThreads();
}
package com.javaspeak.java_examples.concurrency.semaphore;
import java.util.concurrent.Semaphore;
/**
* This Thread Pool will block on executeRunnable(..) for a thread to become available
*
* @author John Dickerson - 23 Dec 2022
*/
public class BlockingThreadPoolImpl implements BlockingThreadPool {
private Semaphore semaphore;
public BlockingThreadPoolImpl( Integer numberThreads ) {
semaphore = new Semaphore( numberThreads );
}
@Override
public int numberFreeThreads() {
// returns number of available permits
return semaphore.availablePermits();
}
@Override
public void executeRunnable( Runnable runnable ) {
try {
// This will block if we have used all the permits
semaphore.acquire();
Thread thread = new Thread() {
public void run() {
try {
runnable.run();
}
finally {
// the permit is added back to the semaphore
semaphore.release();
}
}
};
thread.start();
}
catch( InterruptedException e ) {
}
}
}
package com.javaspeak.java_examples.concurrency.semaphore;
import java.util.concurrent.ExecutionException;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
* @author John Dickerson - 2 Dec 2022
*/
public class SemaphoreExampleTest {
private BlockingThreadPool threadPool;
@BeforeClass
public void setup() {
threadPool = new BlockingThreadPoolImpl( 4 );
}
@Test
public void doTest() throws InterruptedException, ExecutionException {
threadPool.executeRunnable(
new Runnable() {
@Override
public void run() {
try {
Thread.sleep( 1000 );
System.out.println( "Done" );
}
catch( InterruptedException e ) {
}
}
}
);
// Our thread is in process so we have one thread less available
Assert.assertEquals( threadPool.numberFreeThreads(), 3 );
Thread.sleep( 1100 );
// The thread has completed so it should have been given back to the pool
Assert.assertEquals( threadPool.numberFreeThreads(), 4 );
}
}
Back: Concurrency
Page Author: JD