第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

首頁(yè) 慕課教程 Java并發(fā)工具 Java并發(fā)工具 計(jì)數(shù)信號(hào)量 Semaphore

Java 并發(fā)工具之 Semaphore

1. 前言

從本節(jié)開始,我們學(xué)習(xí)新一章內(nèi)容 —— 同步工具。
本節(jié)帶領(lǐng)大家認(rèn)識(shí)第一個(gè)常用的 Java 并發(fā)工具類之 Semaphore。

本節(jié)先通過一個(gè)生活中的例子為大家通俗解釋一下什么是 Semaphore 信號(hào)量,接著介紹 Semaphore 工具類的最基本用法,有了這些基本認(rèn)識(shí)之后,給出 Semaphore 工具最常用的場(chǎng)合說明,然后通過簡(jiǎn)單的編碼實(shí)現(xiàn)文中提到的生活案例,讓大家有一個(gè)理性的認(rèn)識(shí),之后帶領(lǐng)大家熟悉 Semaphore 最常用的一些編程方法,最后通過同類工具的比較,進(jìn)一步加深對(duì) Semaphore 工具類的理解。

Semaphore 工具類本身使用很簡(jiǎn)單,重點(diǎn)是對(duì)常用編程方法的準(zhǔn)確理解。

當(dāng)我們遇到各類需要做并發(fā)控制的場(chǎng)合時(shí),怎么做到選取最合適的并發(fā)工具加以應(yīng)用呢?唯有多加練習(xí),不斷總結(jié)各種并發(fā)工具之間的區(qū)別,透徹理解各類工具的應(yīng)用場(chǎng)合,才能做到游刃有余,手到擒來。

下面我們正式開始介紹吧。

2. 概念解釋

從 JDK1.5 開始提供,Java 官方就在 java.util.concurrent 并發(fā)包中提供了 Semaphore 工具類。

那什么是 “Semaphore” 呢?單詞 “Semaphore” 在計(jì)算機(jī)世界中被解釋為中文 “信號(hào)量” ,但更能表述其含義的叫法應(yīng)該是 “許可證管理器”。不管叫什么中文名稱,它就是一種計(jì)數(shù)信號(hào)量,用于管理一組資源,給資源的使用者規(guī)定一個(gè)量從而控制同一時(shí)刻的使用者數(shù)目。

這樣的解釋是不是很抽象?沒關(guān)系,在此為大家舉一個(gè)生活中通俗的例子,讓大家先對(duì) “信號(hào)量” 及其應(yīng)用有一個(gè)感性的認(rèn)識(shí)。

大家先觀察一下下面過閘機(jī)的圖例,回想一下我們平時(shí)過閘機(jī)的場(chǎng)景。
圖片描述

(圖片來自網(wǎng)絡(luò),圖片版權(quán)歸作者所有)

比如上圖中過閘機(jī)就是信號(hào)量的基本運(yùn)用。

上圖中的乘客就類比是我們程序里面的各類線程,閘機(jī)就類比是一類線程需要使用的資源,而信號(hào)量就是某一時(shí)刻可用的閘機(jī)數(shù)量。

當(dāng)某個(gè)時(shí)刻有乘客需要使用閘機(jī)過站時(shí),首先他需要找到一臺(tái)沒有人使用的閘機(jī),現(xiàn)實(shí)中他通過眼睛觀察即可知道,在我們程序里面就是需要觀察信號(hào)量,看能不能申請(qǐng)到代表可用閘機(jī)的信號(hào)量,如果能則表示有空閑閘機(jī) (資源) 可用,否則需要等待其他乘客使用完畢 (信號(hào)量釋放)后再使用。

概念我們已經(jīng)了解了,那 Semaphore 工具類最基本的用法是怎樣的呢?別急,看下面。

3. 基本用法

// 首先創(chuàng)建 Semaphore 對(duì)象
Semaphore semaphore = new Semaphore();
// 在資源操作開始之前,先獲取資源的使用許可
semaphore.acquire();
...
// 在獲取到資源后,利用資源進(jìn)行業(yè)務(wù)處理
...
// 在資源操作完畢之后,釋放資源的使用許可
semaphore.release();
...

是不是很簡(jiǎn)單,那 Semaphore 信號(hào)量在我們?nèi)粘?shí)踐中,到底應(yīng)該應(yīng)用在哪些場(chǎng)合比較合適呢?下面我們給出最常用的場(chǎng)景說明。

4. 常用場(chǎng)景

Semaphore 經(jīng)常用于限制同一時(shí)刻獲取某種資源的線程數(shù)量,最為典型的就是做流量控制。

比如 WEB 服務(wù)器處理能力有限,需要控制網(wǎng)絡(luò)請(qǐng)求接入的最大連接數(shù),以防止過大的請(qǐng)求流量壓垮我們的服務(wù)器,導(dǎo)致整個(gè)應(yīng)用不能正常提供服務(wù)。

比如數(shù)據(jù)庫(kù)服務(wù)器處理能力有限,需要控制數(shù)據(jù)庫(kù)最大連接數(shù),以防止大量某個(gè)應(yīng)用過分占有數(shù)據(jù)庫(kù)連接數(shù),導(dǎo)致數(shù)據(jù)庫(kù)服務(wù)器不能為其他的應(yīng)用提供足夠的連接請(qǐng)求。

當(dāng)在研發(fā)過程中遇到類似這些場(chǎng)景時(shí),就可以考慮直接應(yīng)用 Semaphore 工具類輔助實(shí)現(xiàn)。

上面舉的生活中過閘機(jī)的例子,如果用程序表達(dá),該如何實(shí)現(xiàn)呢?在程序中如何使用 Semaphore 信號(hào)量達(dá)到控制和應(yīng)用呢?最直接方式就是去感受最簡(jiǎn)單的例子,下面直接用最明了的代碼說明例子中如何應(yīng)用了信號(hào)量。

5. 場(chǎng)景案例

import java.util.concurrent.Semaphore;

public class SemaphoreTest {

    // 先定義一個(gè)Semaphore信號(hào)量對(duì)象
    private static Semaphore semaphore = new Semaphore(3);

    // 測(cè)試方法
    public static void main(String[] args) {

        // 定義10個(gè)人過閘機(jī)
        for(int i=0; i<10; i++) {
            Person person = new Person(semaphore, i);
            new Thread(person).start();
        }
    }
}

在上面的代碼中,先創(chuàng)建了一個(gè) Semaphore 信號(hào)量對(duì)象,然后賦給了每一位進(jìn)站旅客 Person ,接下來每一位旅客如何動(dòng)作呢,看下面的代碼。

import java.util.concurrent.Semaphore;

public class Person implements Runnable {

    private Semaphore semaphore;
    private String persionName;

    public Person(Semaphore semaphore, int persionNo) {
        this.semaphore = semaphore;
        this.persionName = "旅客" + persionNo;
    }

    public void run() {
        try {
            // 請(qǐng)求獲得信號(hào)量,就是請(qǐng)求(尋找)是否有可用的閘機(jī)
            semaphore.acquire();
            // 已經(jīng)等到了可用閘機(jī)
            System.out.println(this.persionName + "已經(jīng)占有一臺(tái)閘機(jī)");
            // 進(jìn)站
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 已經(jīng)進(jìn)站
            System.out.println(this.persionName + "已經(jīng)進(jìn)站");
            // 讓出閘機(jī)給別人用
            semaphore.release();
        }
    }
}

在 Person 類中,首先通過 acquire 獲取了可用閘機(jī),然后休眠 2 秒代表刷卡過閘機(jī),最后在 finally 使用 release 方法讓出閘機(jī)。我們觀察一下運(yùn)行結(jié)果。

旅客0已經(jīng)占有一臺(tái)閘機(jī)  <---占據(jù)了一臺(tái)
旅客1已經(jīng)占有一臺(tái)閘機(jī)  <---占據(jù)了一臺(tái)
旅客6已經(jīng)占有一臺(tái)閘機(jī)  <---占據(jù)了一臺(tái)
旅客0已經(jīng)進(jìn)站         <---0號(hào)旅客已經(jīng)進(jìn)站釋放了閘機(jī)
旅客3已經(jīng)占有一臺(tái)閘機(jī)  <---3號(hào)旅客這個(gè)時(shí)候才拿到了可用閘機(jī)
旅客1已經(jīng)進(jìn)站         <---1號(hào)旅客已經(jīng)進(jìn)站釋放了閘機(jī)
旅客2已經(jīng)占有一臺(tái)閘機(jī)  <---2號(hào)旅客這個(gè)時(shí)候才拿到了可用閘機(jī)
旅客6已經(jīng)進(jìn)站         <---6號(hào)旅客已經(jīng)進(jìn)站釋放了閘機(jī)
旅客4已經(jīng)占有一臺(tái)閘機(jī)  <---4號(hào)旅客這個(gè)時(shí)候才拿到了可用閘機(jī)
旅客3已經(jīng)進(jìn)站
旅客4已經(jīng)進(jìn)站
旅客5已經(jīng)占有一臺(tái)閘機(jī)
旅客7已經(jīng)占有一臺(tái)閘機(jī)
旅客2已經(jīng)進(jìn)站
旅客8已經(jīng)占有一臺(tái)閘機(jī)
旅客7已經(jīng)進(jìn)站
旅客5已經(jīng)進(jìn)站
旅客9已經(jīng)占有一臺(tái)閘機(jī)
旅客8已經(jīng)進(jìn)站
旅客9已經(jīng)進(jìn)站

觀察結(jié)果發(fā)現(xiàn),同一時(shí)刻最多只能有 3 位旅客占用閘機(jī)進(jìn)站,其他旅客需要等待其進(jìn)站后讓出閘機(jī)才能刷卡進(jìn)站。

至此,大家對(duì)信號(hào)量已經(jīng)有了初步的理解,接下來我們繼續(xù)豐富對(duì) Semaphore 工具類的認(rèn)識(shí)。

6. 其他方法介紹

除過上面代碼中使用的最基本的 acquire 方法和 release 方法之外,我們還需要掌握其他幾個(gè)核心方法的使用。下面逐個(gè)介紹。

  1. Semaphore(int permits, boolean fair)

上面的例子中使用了 Semaphore (int permits) 構(gòu)造方法。
此構(gòu)造方法也是用于創(chuàng)建信號(hào)量對(duì)象,第二個(gè)參數(shù)表示創(chuàng)建的信號(hào)量是否秉持公平競(jìng)爭(zhēng)特性。即對(duì)資源的申請(qǐng)使用嚴(yán)格按照申請(qǐng)的順序給予允許。

一般情況下,我們使用 Semaphore (int permits) 構(gòu)造方法就可以了。

  1. availablePermits()

返回當(dāng)前還可用的許可數(shù),即還允許多少個(gè)線程進(jìn)行使用資源。套用在上面的例子中,就是返回當(dāng)前還有多少臺(tái)閘機(jī)空閑可用。

int availablePermits = semaphore.availablePermits();
System.out.println("當(dāng)前可用閘機(jī)數(shù)" + availablePermits);

>>運(yùn)行結(jié)果:
當(dāng)前可用閘機(jī)數(shù)2
旅客0已經(jīng)占有一臺(tái)閘機(jī)
當(dāng)前可用閘機(jī)數(shù)1
旅客1已經(jīng)占有一臺(tái)閘機(jī)
......
  1. hasQueuedThreads()

返回是否有線程正在等待獲取資源。也就是返回當(dāng)前是否有人在排隊(duì)等待過閘機(jī)。

boolean hasQueuedThreads = semaphore.hasQueuedThreads();
System.out.println("當(dāng)前是否有旅客等待閘機(jī)進(jìn)站:"+hasQueuedThreads);

>>運(yùn)行結(jié)果:
當(dāng)前是否有旅客等待閘機(jī)進(jìn)站:false
旅客0已經(jīng)占有一臺(tái)閘機(jī)
當(dāng)前是否有旅客等待閘機(jī)進(jìn)站:false
旅客1已經(jīng)占有一臺(tái)閘機(jī)
當(dāng)前是否有旅客等待閘機(jī)進(jìn)站:false
旅客2已經(jīng)占有一臺(tái)閘機(jī)
  1. acquire(int permits)

申請(qǐng)指定數(shù)目的信號(hào)量許可,在獲取不到指定數(shù)目的許可時(shí)將一直阻塞。就好比一個(gè)旅客需要同時(shí)占用兩個(gè)閘機(jī)過站。類似的 release (int permits) 方法用于釋放指定數(shù)目的信號(hào)量許可。

acquire (int permits) 同上面例子中使用的 acquire () 最大的區(qū)別就是用于一次性申請(qǐng)多個(gè)許可,當(dāng)參數(shù) permits = 1 時(shí),兩者相同。release (int permits) 和 release () 也是類似。

  1. tryAcquire()

嘗試申請(qǐng)信號(hào)量許可,無論是否申請(qǐng)成功都返回申請(qǐng)結(jié)果。當(dāng)申請(qǐng)成功時(shí)返回 true , 否則返回 false 。程序里面根據(jù)申請(qǐng)結(jié)果決定后繼的處理流程。和 acquire () 的主要區(qū)別在于,不會(huì)阻塞立刻返回。

同類功能的方法還有 tryAcquire (int permits) 、tryAcquire (long timeout, TimeUnit unit) 、tryAcquire (int permits, long timeout, TimeUnit unit) 。這些方法實(shí)現(xiàn)的功能一樣,只是可以更加精細(xì)化地控制對(duì)資源申請(qǐng),比如申請(qǐng)超時(shí)控制、申請(qǐng)?jiān)S可數(shù)量。

7. 工具對(duì)比

大家可能有一個(gè)疑問了,Semaphore 好像和 synchronized 關(guān)鍵字沒什么區(qū)別,都可以實(shí)現(xiàn)同步。

其實(shí)不然,synchronized 真正用于并發(fā)控制,確保對(duì)某一個(gè)資源的串行訪問;而 Semaphore 限制訪問資源的線程數(shù),其實(shí)并沒有實(shí)現(xiàn)同步,只有當(dāng) Semaphore 限制的資源同時(shí)只允許一個(gè)線程訪問時(shí),兩者達(dá)到的效果一樣。

大家記住,Semaphore 和 synchronized 最主要的差別是 Semaphore 可以控制一個(gè)或多個(gè)并發(fā),而 synchronized 只能是一個(gè)。這一點(diǎn)需要大家好好琢磨。

還是通過上面的例子的運(yùn)行結(jié)果給大家做一下解釋。

>>運(yùn)行結(jié)果:
旅客0已經(jīng)占有一臺(tái)閘機(jī)  <-------
旅客1已經(jīng)占有一臺(tái)閘機(jī)  | 觀察發(fā)現(xiàn)同時(shí)有多個(gè)并發(fā)執(zhí)行,而非串行的一個(gè)旅客過完閘機(jī)后才輪到下一個(gè)旅客。
旅客2已經(jīng)占有一臺(tái)閘機(jī)  <-------
......

8. 小結(jié)

本節(jié)通過一個(gè)簡(jiǎn)單的例子,介紹了 Semaphore 的基本用法。另外對(duì)一些核心方法做了簡(jiǎn)單介紹并給出應(yīng)用場(chǎng)景。希望大家在學(xué)習(xí)過程中,多思考勤練習(xí),早日掌握之。