Semaphore是一種在多線程環境下使用的設施,該設施負責協調各個線程,以保證它們能夠正确、合理的使用公共資源的設施,也是作業系統中用于控制程序同步互斥的量。
Semaphore類是一個計數信号量,必須由擷取它的線程釋放, 通常用于限制可以通路某些資源(實體或邏輯的)線程數目。
一個信号量有且僅有3種操作,且它們全部是原子的:初始化、增加和減少
增加可以為一個程序解除阻塞;
減少可以讓一個程序進入阻塞。
以一個資料庫連接配接池為例。假設連接配接池隻有10個連接配接數,一開始有10個可用連接配接數。這時如果同時來了50個線程,連接配接池允許其中10個線程不受阻礙的擷取連接配接,剩下的線程必須等待,再有新來的線程也需要等待。這時,有一個線程釋放了連接配接,連接配接池會允許一個線程進入擷取連接配接,如果又有兩個線程釋放連接配接,則又可以進入兩個線程,如此往複。
代碼示範:
import java.util.LinkedList;
import java.util.Random;
import java.util.concurrent.Semaphore;
public class UseSemaphore {
public static void main(String[] args) {
for (int i=0;i<50;i++){
new Thread(new Runnable() {
@Override
public void run() {
//讓每個線程持有連接配接的時間不一樣
Random random = new Random();
long start = System.currentTimeMillis();
try {
String connect = takeConn();
System.out.println("Thread_"+Thread.currentThread().getId()
+"_擷取資料庫連接配接共耗時【"+(System.currentTimeMillis()-start)+"】ms.");
//模拟業務操作,線程持有連接配接查詢資料
Thread.sleep(100+random.nextInt(100));
System.out.println("查詢資料完成,歸還連接配接!");
returnConn(connect);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
//可用連接配接數
private final static Semaphore useful = new Semaphore(10);
//已用連接配接數
private final static Semaphore useless = new Semaphore(0);
//模拟資料庫連接配接池
private static LinkedList<String> pool = new LinkedList<>();
//初始化連接配接池
static {
for (int i=1;i<=10;i++){
pool.addLast("connection"+i);
}
}
//歸還連接配接
public static void returnConn(String conn) throws InterruptedException {
if(conn!=null) {
System.out.println("目前有"+useful.getQueueLength()+"個線程等待資料庫連接配接!!"
+"可用連接配接數:"+useful.availablePermits());
//擷取已用連接配接數許可,相當于useless-1
useless.acquire();
synchronized (pool) {
pool.addLast(conn);
}
//釋放可用連接配接數許可,相當于useful+1
useful.release();
}
}
//擷取連接配接
public static String takeConn() throws InterruptedException {
//擷取可用連接配接數許可,相當于useful-1
useful.acquire();
String conn;
synchronized (pool) {
conn = pool.removeFirst();
}
//釋放已用連接配接數許可,相當于useless+1
useless.release();
return conn;
}
}