標籤:
Semaphore 訊號量主要用於約束多個線程可同時擷取的物理上的或者邏輯上的資源數。比如用在各種池的設計中。
訊號量用於管理這些資源的一個虛擬管理認證。線程在擷取一個資源時,首先要擷取一個資源的許可憑證。當線程用完之後將資源返回池中,並將許可憑證返回給訊號量。
例如:
一個池的例子:
class Pool {
private static final int MAX_AVAILABLE = 100;//最大可用資源數
private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);
public Object getItem() throws InterruptedException {
available.acquire();
return getNextAvailableItem();
}
public void putItem(Object x) {
if (markAsUnused(x))
available.release();
}
// Not a particularly efficient data structure; just for demo
protected Object[] items = ... whatever kinds of items being managed
protected boolean[] used = new boolean[MAX_AVAILABLE];//是否被使用
protected synchronized Object getNextAvailableItem() {
for (int i = 0; i < MAX_AVAILABLE; ++i) {
if (!used[i]) {
used[i] = true;
return items[i];
}
}
return null; // not reached
}
protected synchronized boolean markAsUnused(Object item) {
for (int i = 0; i < MAX_AVAILABLE; ++i) {
if (item == items[i]) {
if (used[i]) {
used[i] = false;
return true;
} else
return false;
}
}
return false;
}
}}
訊號量初始化時有兩個參數,第一個參數是資源可用數目,第二個是fairness parameter。fairness parameter 是公平變數。設為false那麼,當有一個線程請求acquire時,會直接分給這個線程,而不管等待隊列中焦急等待的眾線程。而公平指的當然就是先來先服務了,如果沒擷取到一個許可,線程就只好先把自己掛起來了。但是使用tryacquire則直接搶一個許可憑證。調用一個acquire()並不意味著必須調用release(),即java不要求其成對出現,但是保證代碼正確,就靠自己的程式設計了。
一下是我自己寫的一個訊號量的例子:
package com;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Semaphore;
class Test
{
private final Semaphore sem;
private final Set<String> set;
public Test(int bound)
{
this.set = Collections.synchronizedSet(new HashSet<String>());
this.sem=new Semaphore(bound,true);
}
public boolean add(String str) throws InterruptedException
{
boolean result = false;
sem.acquire();
try{
result=set.add(str);
}finally{
if(!result)
{
sem.release();
}
}
return result;
}
public boolean remove(String str)
{
boolean result=set.remove(str);
if(result)
{
sem.release();
}
return result;
}
}
public class Main{
public static void main(String[] args)
{
Test test = new Test(10);
new Thread(){
public void run()
{
int j=0;
for(int i=20;i<40;)
{
System.out.println("Thread1 run");
try {
test.add(String.valueOf(i));
System.out.println("Thread1 add"+(i++));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("Thread1 stop");
}
}.start();
new Thread(){
public void run()
{
int j=0;
boolean result=false;
for(int i=0;i<20;)
{
System.out.println("Thread2 run");
try {
result=test.add(String.valueOf(i));
if(result)System.out.println("Thread2 add"+(i++));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("Thread2 stop");
}
}.start();
new Thread(){
public void run()
{
int i=0,j=0;
boolean result=false;
while(i<40)
{
j++;
j=j%40;
System.out.println("Thread3 run");
result=test.remove(String.valueOf(j));
if(result)System.out.println("remove"+(i++));
}
System.out.println("Thread3 stop");
}
}.start();
}
}
java 訊號量Semaphore