java併發之同步輔助類semaphore

semaphore(seməˌfôr)含義:

信號量就是可以聲明多把鎖(包括一把鎖:此時爲互斥信號量)。
舉個例子:一個房間如果只能容納5個人,多出來的人必須在門外面等着。如何去做呢?一個解決辦法就是:房間外面掛着五把鑰匙,每進去一個人就取走一把鑰匙,沒有鑰匙的不能進入該房間而是在外面等待。每出來一個人就把鑰匙放回原處以方便別人再次進入。
這裏寫圖片描述
常用方法
acquire():獲取信號量,信號量內部計數器減1
release():釋放信號量,信號量內部計數器加1
tryAcquire():這個方法試圖獲取信號量,如果能夠獲取返回true,否則返回false
信號量控制的線程數量在聲明時確定。例如:
Semphore s = new Semphore(2);
一個例子
實現一個功能:一個打印隊列,被三臺打印機打印

package semaphore;

import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class PrintQueue {
    //信號量
    private Semaphore semaphore;

//是否空閒打印機
private boolean freePrinters[];

private Lock lockPrinters;

public PrintQueue(){
    //初始化三個信號
    semaphore=new Semaphore(3);
    //三臺空閒打印機
    freePrinters=new boolean[3];
    for (int i=0; i<3; i++){
        freePrinters[i]=true;
    }
    lockPrinters=new ReentrantLock();
}

public void printJob (Object document){
    try {
        //獲取信號量
        semaphore.acquire();

        int assignedPrinter=getPrinter();

        Long duration=(long)(Math.random()*10);
        System.out.printf("%s: PrintQueue: Printing a Job in Printer %d during %d seconds\n",Thread.currentThread().getName(),assignedPrinter,duration);
        TimeUnit.SECONDS.sleep(duration);

        freePrinters[assignedPrinter]=true;
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        // Free the semaphore
        semaphore.release();            
    }
}
private int getPrinter() {
    int ret=-1;

    try {
        lockPrinters.lock();
        for (int i=0; i<freePrinters.length; i++) {
            if (freePrinters[i]){
                ret=i;
                freePrinters[i]=false;
                break;
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        lockPrinters.unlock();
    }
    return ret;
}

}

聲明一個Job類,使用打印隊列:

package semaphore;

public class Job implements Runnable {

     private PrintQueue printQueue;

      public Job(PrintQueue printQueue){
          this.printQueue=printQueue;
     }

      @Override
      public void run() {
         System.out.printf("%s: Going to print a job\n",Thread.currentThread().getName());
         printQueue.printJob(new Object());
         System.out.printf("%s: The document has been printed\n",Thread.currentThread().getName());        
     }
}

測試:

package semaphore;

public class MainCmd {
public static void main (String args[]){

    PrintQueue printQueue=new PrintQueue();
    //啓動12個打印線程
    Thread thread[]=new Thread[12];
    for (int i=0; i<12; i++){
        thread[i]=new Thread(new Job(printQueue),"Thread "+i);
    }
    for (int i=0; i<12; i++){
        thread[i].start();
    }
}

}

需要注意的地方
1、對於信號量聲明的臨界區,雖然可以控制線程訪問的數量,但是不能保證代碼塊之間是線程安全的。所以上面的例子在方法printJob()方法裏面使用了鎖保證數據安全性。
2、信號量也涉及到公平性問題。和鎖公平性一樣,這裏默認是非公平的。可以通過構造器顯示聲明鎖的公平性。
public Semaphore(int permits, boolean fair)

應用場景
流量控制,即控制能夠訪問的最大線程數。

海量視頻獲取 vue視頻 angular視頻
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章