Semaphore
In this chapter you will learn:
What is Semaphore
Semaphore acts as a permit. The thread that wants access to the shared resource tries to acquire a permit. If the semaphore's count is greater than zero, then the thread is able to get a permit. Once a thread gets the permit, the semaphore's count decrements. Otherwise, the thread will be blocked until a permit can be acquired.
When the thread no longer needs access to the shared resource, it releases the permit. Repleasing the permit causes the semaphore's count to be incremented.
Java's Semaphore class implements this mechanism.
Semaphore has the two constructors shown here:
Semaphore(int num)
Semaphore(int num, boolean how)
num
specifies the initial permit count.
which is the number of threads that can access a shared resource at any one time.
If num
is one, then only one thread can
accessthe resource at any one time.
By default, waiting threads are granted a permit in an
undefined order.
By setting how to true, you can ensure that waiting threads are granted
a permit in the order in which they requested access.
To acquire a permit, call the acquire()
method, which has these two forms:
void acquire( ) throws InterruptedException
acquires one permitvoid acquire(int num) throws InterruptedException
acquires num permits
If the permit cannot be granted at the time of the call, then the invoking thread suspends until the permit is available.
To release a permit, call release()
, which has these two forms:
void release( )
releases one permit.void release(int num)
releases the number of permits specified by num.
import java.util.concurrent.Semaphore;
// j a v a 2s . c o m
public class Main {
public static void main(String args[]) throws Exception {
Semaphore sem = new Semaphore(1, true);
Thread thrdA = new Thread(new SyncOutput(sem, "Message 1"));
Thread thrdB = new Thread(new SyncOutput(sem, "Message 2!"));
thrdA.start();
thrdB.start();
thrdA.join();
thrdB.join();
}
}
class SyncOutput implements Runnable {
Semaphore sem;
String msg;
SyncOutput(Semaphore s, String m) {
sem = s;
msg = m;
}
public void run() {
try {
sem.acquire();
System.out.println(msg);
Thread.sleep(10);
} catch (Exception exc) {
System.out.println("Error Writing File");
}
sem.release();
}
}
The code above generates the following result.
A producer and consumer that use semaphores
An implementation of a producer and consumer that use semaphores to control synchronization.
A shorter version.
import java.util.concurrent.Semaphore;
//from jav a 2 s . co m
public class Main {
public static void main(String args[]) {
Semaphore sem = new Semaphore(1);
new Producer(sem, "A");
new Consumer(sem, "B");
}
}
class Shared {
static int count = 0;
}
class Producer implements Runnable {
String name;
Semaphore sem;
Producer(Semaphore s, String n) {
sem = s;
name = n;
new Thread(this).start();
}
public void run() {
try {
sem.acquire();
for (int i = 0; i < 5; i++) {
System.out.println(name + ": " + Shared.count++);
Thread.sleep(1000);
}
} catch (InterruptedException exc) {
System.out.println(exc);
}
sem.release();
}
}
class Consumer implements Runnable {
String name;
Semaphore sem;
Consumer(Semaphore s, String n) {
sem = s;
name = n;
new Thread(this).start();
}
public void run() {
try {
sem.acquire();
for (int i = 0; i < 5; i++) {
System.out.println(name + ": " + Shared.count--);
Thread.sleep(1000);
}
} catch (InterruptedException exc) {
System.out.println(exc);
}
sem.release();
}
}
The code above generates the following result.
A longer version.
import java.util.concurrent.Semaphore;
public class Main {
public static void main(String args[]) {
Queue queue = new Queue();
new Consumer(queue);
new Producer(queue);
}//j a va 2 s. com
}
class Producer extends Worker {
Producer(Queue q) {
super(q);
}
public void run() {
for (int i = 0; i < 20; i++)
queue.produce(i);
}
}
class Consumer extends Worker{
Consumer(Queue q) {
super(q);
}
public void run() {
for (int i = 0; i < 20; i++)
queue.consume();
}
}
abstract class Worker implements Runnable {
Queue queue;
Worker(Queue q) {
this.queue = q;
new Thread(this, "Consumer").start();
}
}
class Queue {
int currentValue;
// Start with consumer semaphore unavailable.
static Semaphore semaphoreConsumer = new Semaphore(0);
static Semaphore semaphoreProducer = new Semaphore(1);
void consume() {
try {
semaphoreConsumer.acquire();
} catch (Exception e) {
System.out.println("Exception caught");
}
System.out.println("consume: " + currentValue);
semaphoreProducer.release();
}
void produce(int n) {
try {
semaphoreProducer.acquire();
} catch (Exception e) {
System.out.println("Exception caught");
}
this.currentValue = n;
System.out.println("produce: " + n);
semaphoreConsumer.release();
}
}
The code above generates the following result.
Next chapter...
What you will learn in the next chapter: