天天看點

Semaphore 案例

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;
    }


}
           

繼續閱讀