Semaphore is a class in java.util.concurrent package introduced in JDK 5. Semaphore basically maintains a set of permits, so there are two methods which are mainly used for semaphore.
- acquire
- release
acquire() method is used to get a permit and if no. of permits reaches max allowed permits then thread has to wait to get permit which will be released by some other thread by calling release() method.
Semaphores are generally used to restrict the number of threads to access resources.
Real time examples:
- Semaphores can be used to restrict number of database connections at a time
- Semaphores can also be used to bound any collection.
Example:
We will create a class BoundedArrayList which can have only 5 elements at a time. If any thread wants to add more element to the list, thread will have to wait until any other thread remove elements from the list.
When we add an element to the list, we will call semaphore.acquire and when we remove an element from the list, we will call semaphore.release.
Create a class called BoundedArrayList.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
package org.arpit.java2blog.bean;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Semaphore;
public class BoundedArrayList {
private final Semaphore semaphore;
private List arraylist;
BoundedArrayList(int limit) {
this.arraylist = Collections.synchronizedList(new ArrayList());
semaphore = new Semaphore(limit);
}
/*
* Add element to the list and call semaphore.acquire method
* */
public boolean add(T t) throws InterruptedException {
boolean added = false;
semaphore.acquire();
try {
added = arraylist.add(t);
return added;
} finally {
if (!added)
semaphore.release();
}
}
/*
* remove element from the list and call semaphore.release method
* */
public boolean remove(T t) {
boolean wasRemoved = arraylist.remove(t);
if (wasRemoved)
semaphore.release();
return wasRemoved;
}
public void remove(int index) {
arraylist.remove(index);
semaphore.release();
}
public List getArraylist() {
return arraylist;
}
public Semaphore getSemaphore() {
return semaphore;
}
}
|
Create a main class BoundedArrayListMain.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
package org.arpit.java2blog.bean;
public class BoundedArrayListMain {
public static void main(String[] args) throws InterruptedException {
final BoundedArrayList ba = new BoundedArrayList(5);
Runnable runnable1 = new Runnable() {
@Override
public void run() {
try {
ba.add("John");
ba.add("Martin");
ba.add("Adam");
ba.add("Prince");
ba.add("Tod");
System.out.println("Available Permits : "+ba.getSemaphore().availablePermits());
ba.add("Tony");
System.out.println("Final list: "+ba.getArraylist());
} catch (InterruptedException ie) {
}
}
};
Runnable runnable2 = new Runnable() {
@Override
public void run() {
try {
System.out.println("Before removing elements: "+ ba.getArraylist());
Thread.sleep(5000);
ba.remove("Martin");
ba.remove("Adam");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Thread t1 = new Thread(runnable1);
Thread t2 = new Thread(runnable2);
t1.start();
t2.start();
}
}
|
When you run above program, you will get below output:
1
2
3
4
5
|
Available Permits : 0
Before removing elements: [John, Martin, Adam, Prince, Tod]
Final list: [John, Prince, Tod, Tony]
|
Explanation:
- We have created two thread t1 and t2.
- t1 and t2 both share common list reference ba.
- When t1 adds 5 elements to the list, available permits became 0.
- Now t1 waits for another thread to remove elements, so that semaphore have some available permits.
- Another thread t2 removes elements from the list after waiting for 5 secs.
- Once t2 removes elements, t1 adds “Tony” to list.