亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

詳解Java中信號量Semaphore的使用

 更新時間:2024年01月14日 08:14:56   作者:宋小黑  
在Java中,正確地管理并發(fā)是一件既挑戰(zhàn)又有趣的事情,當(dāng)談到并發(fā)控制,就不得不說Java中的一個非常強(qiáng)大的工具,就是Semaphore,下面我們就來看看Java中信號量Semaphore的具體使用吧

第1章:引言

大家好,我是小黑。今天,咱們一起來深入探討一下Semaphore。在Java中,正確地管理并發(fā)是一件既挑戰(zhàn)又有趣的事情。當(dāng)談到并發(fā)控制,大家可能首先想到的是synchronized關(guān)鍵字或者是ReentrantLock。但其實,Java還提供了一個非常強(qiáng)大的工具,就是Semaphore。

Semaphore,直譯過來就是“信號量”。在日常生活中,信號燈控制著車輛的通行,防止交通混亂,這其實和Semaphore在程序中的作用頗為相似。Semaphore主要用于控制同時訪問特定資源的線程數(shù)量,它通過協(xié)調(diào)各個線程,保證合理的使用公共資源。比方說如果有一家餐館只允許固定數(shù)量的顧客同時用餐,這就是Semaphore的經(jīng)典應(yīng)用場景。

第2章:Semaphore的基本概念

讓我們先來了解一下Semaphore的基本概念。在Java中,Semaphore是位于java.util.concurrent包下的一個類。它的核心就是維護(hù)了一個許可集。簡單來說,就是有一定數(shù)量的許可,線程需要先獲取到許可,才能執(zhí)行,執(zhí)行完畢后再釋放許可。

那么,這個許可是什么呢?其實,你可以把它想象成是對資源的訪問權(quán)。比如,有5個許可,就意味著最多允許5個線程同時執(zhí)行。線程可以通過acquire()方法來獲取許可,如果沒有可用的許可,該線程就會阻塞,直到有許可可用。

讓我們看個簡單的例子。假設(shè)咱們有一個限制了最多同時3個線程執(zhí)行的Semaphore:

import java.util.concurrent.Semaphore;

public class SemaphoreExample {
    // 創(chuàng)建一個Semaphore實例,許可數(shù)量為3
    private static final Semaphore semaphore = new Semaphore(3);

    public static void main(String[] args) {
        // 創(chuàng)建并啟動三個線程
        for (int i = 1; i <= 3; i++) {
            new Thread(new Task(semaphore), "線程" + i).start();
        }
    }

    static class Task implements Runnable {
        private final Semaphore semaphore;

        public Task(Semaphore semaphore) {
            this.semaphore = semaphore;
        }

        @Override
        public void run() {
            try {
                // 請求許可
                semaphore.acquire();
                System.out.println(Thread.currentThread().getName() + " 獲取許可,正在執(zhí)行");
                Thread.sleep(1000); // 模擬任務(wù)執(zhí)行
                System.out.println(Thread.currentThread().getName() + " 執(zhí)行完畢,釋放許可");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } finally {
                // 釋放許可
                semaphore.release();
            }
        }
    }
}

在這個例子中,咱們創(chuàng)建了一個Semaphore實例,設(shè)置最大許可數(shù)為3。這意味著,最多只能有3個線程同時運(yùn)行Task中的代碼。每個線程在開始執(zhí)行前,都會嘗試通過acquire()方法獲取一個許可。

第3章:Semaphore的核心原理

現(xiàn)在,咱們深入一下Semaphore的核心原理。理解這個原理對于掌握Semaphore的高效使用至關(guān)重要。在Java中,Semaphore不僅僅是個計數(shù)器,它背后的原理和實現(xiàn)邏輯比看起來要復(fù)雜得多。

Semaphore的核心是基于AQS(AbstractQueuedSynchronizer)這個框架。AQS是Java并發(fā)包中的一個非常重要的組件,它用來構(gòu)建鎖或者其他同步器。簡單來說,AQS提供了一種機(jī)制,可以讓線程在訪問某個資源前進(jìn)入等待狀態(tài),并在資源可用時被喚醒。這正是Semaphore的基礎(chǔ)。

Semaphore維護(hù)了一個許可集,這個集合的大小在初始化時設(shè)定。每次調(diào)用acquire()方法,Semaphore會試圖從這個集合中取出一個許可。如果沒有可用的許可,線程就會被阻塞,直到有其他線程釋放一個許可。相反,release()方法會增加許可的數(shù)量,并有可能喚醒等待的線程。

讓小黑通過一段代碼來更好地說明這個原理:

import java.util.concurrent.Semaphore;

public class SemaphoreDeepDive {
    public static void main(String[] args) {
        // 初始化一個只有2個許可的Semaphore
        Semaphore semaphore = new Semaphore(2);

        Runnable task = () -> {
            try {
                // 嘗試獲取許可
                semaphore.acquire();
                System.out.println("線程 " + Thread.currentThread().getName() + " 獲取了許可");
                // 模擬任務(wù)執(zhí)行
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } finally {
                // 釋放許可
                semaphore.release();
                System.out.println("線程 " + Thread.currentThread().getName() + " 釋放了許可");
            }
        };

        // 創(chuàng)建并啟動3個線程
        for (int i = 0; i < 3; i++) {
            new Thread(task).start();
        }
    }
}

在這個例子中,Semaphore被初始化為只有兩個許可。當(dāng)三個線程嘗試運(yùn)行時,只有兩個能夠同時執(zhí)行。第三個線程必須等待,直到一個許可被釋放。這就是Semaphore控制并發(fā)的機(jī)制。

第4章:使用Semaphore的場景

咱們來聊聊Semaphore在實際編程中的應(yīng)用場景。理解了Semaphore的基礎(chǔ)和原理后,咱們現(xiàn)在可以探索它在實際場景中的具體使用。Semaphore非常靈活,可以用于多種場合,特別是在控制資源訪問的并發(fā)環(huán)境中。

場景一:資源池

想象一下,小黑有一個數(shù)據(jù)庫連接池,這個池子里只有幾個數(shù)據(jù)庫連接。如果所有的連接都被占用了,其他需要數(shù)據(jù)庫連接的線程就得等待。這就是Semaphore的經(jīng)典應(yīng)用場景。通過限制可用的連接數(shù)量,Semaphore確保了不會有太多的線程同時訪問數(shù)據(jù)庫。

場景二:限流

在Web服務(wù)中,咱們可能想要限制某個服務(wù)的并發(fā)請求數(shù)量,以防止服務(wù)器過載。Semaphore可以很容易地實現(xiàn)這個功能。設(shè)置一個固定數(shù)量的許可,就可以限制同時處理的請求數(shù)量。

代碼示例

讓小黑用代碼展示一下這些場景。首先,是一個簡單的數(shù)據(jù)庫連接池的示例:

import java.util.concurrent.Semaphore;

public class DatabaseConnectionPool {
    private final Semaphore semaphore;
    private final String[] connectionPool;
    private final boolean[] used;

    public DatabaseConnectionPool(int poolSize) {
        semaphore = new Semaphore(poolSize);
        connectionPool = new String[poolSize];
        used = new boolean[poolSize];
        for (int i = 0; i < poolSize; i++) {
            connectionPool[i] = "連接 " + (i + 1);
        }
    }

    public String getConnection() throws InterruptedException {
        semaphore.acquire();
        return getNextAvailableConnection();
    }

    public void releaseConnection(String connection) {
        if (markAsUnused(connection)) {
            semaphore.release();
        }
    }

    private synchronized String getNextAvailableConnection() {
        for (int i = 0; i < connectionPool.length; i++) {
            if (!used[i]) {
                used[i] = true;
                return connectionPool[i];
            }
        }
        return null; // 不應(yīng)該發(fā)生,semaphore保證了有可用連接
    }

    private synchronized boolean markAsUnused(String connection) {
        for (int i = 0; i < connectionPool.length; i++) {
            if (connection.equals(connectionPool[i])) {
                used[i] = false;
                return true;
            }
        }
        return false;
    }
}

這個代碼演示了如何使用Semaphore來控制對有限數(shù)量資源(數(shù)據(jù)庫連接)的訪問。每個連接在使用前需要獲得一個許可,使用完后釋放許可。

第5章:Semaphore的高級特性

公平性與非公平性

Semaphore有兩種模式:公平模式和非公平模式。公平模式下,線程獲得許可的順序與它們請求許可的順序一致,就像排隊一樣。而非公平模式則沒有這種保證,線程可以“插隊”,這可能會導(dǎo)致某些線程等待時間過長。

在Java中,創(chuàng)建Semaphore時可以指定是公平模式還是非公平模式。默認(rèn)情況下,Semaphore是非公平的。公平模式通常會有更高的性能開銷,因為它需要維護(hù)一個更加復(fù)雜的內(nèi)部結(jié)構(gòu)來保證順序。

可中斷操作

在Semaphore中,等待許可的操作可以是可中斷的。這意味著如果一個線程在等待一個許可時被中斷,它可以選擇退出等待。這在處理某些需要響應(yīng)中斷的場景時非常有用。

代碼示例

讓小黑給你演示一下這兩個特性的代碼實例:

import java.util.concurrent.Semaphore;

public class SemaphoreAdvancedFeatures {
    public static void main(String[] args) throws InterruptedException {
        // 創(chuàng)建一個公平模式的Semaphore
        Semaphore fairSemaphore = new Semaphore(1, true);

        // 創(chuàng)建并啟動兩個線程
        Thread t1 = new Thread(new Worker(fairSemaphore), "線程1");
        Thread t2 = new Thread(new Worker(fairSemaphore), "線程2");
        t1.start();
        t2.start();

        // 演示可中斷操作
        Thread interruptibleThread = new Thread(() -> {
            try {
                fairSemaphore.acquire();
                System.out.println(Thread.currentThread().getName() + " 獲取了許可");
            } catch (InterruptedException e) {
                System.out.println(Thread.currentThread().getName() + " 被中斷");
            }
        });
        interruptibleThread.start();
        Thread.sleep(1000); // 等待一會
        interruptibleThread.interrupt(); // 中斷線程
    }

    static class Worker implements Runnable {
        private final Semaphore semaphore;

        Worker(Semaphore semaphore) {
            this.semaphore = semaphore;
        }

        @Override
        public void run() {
            try {
                semaphore.acquire();
                System.out.println(Thread.currentThread().getName() + " 獲取了許可");
                Thread.sleep(2000); // 模擬工作
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } finally {
                semaphore.release();
                System.out.println(Thread.currentThread().getName() + " 釋放了許可");
            }
        }
    }
}

在這個代碼中,小黑創(chuàng)建了一個公平模式的Semaphore,并演示了兩個線程按順序獲取許可的情況。同時,還展示了一個線程在嘗試獲取許可時如何被中斷。

第6章:Semaphore的問題與解決方案

問題一:資源耗盡

最常見的問題之一是資源耗盡。當(dāng)所有許可都被占用,并且持有許可的線程因某種原因無法釋放許可時,就會出現(xiàn)資源耗盡的情況。這可能會導(dǎo)致其他線程永久等待,從而造成死鎖。

解決方案:確保在使用資源后總是釋放許可。可以使用try-finally塊來確保即使在發(fā)生異常時也能釋放許可。

問題二:公平性問題

如前所述,Semaphore可以是公平的或非公平的。在非公平模式下,有可能導(dǎo)致某些線程饑餓,即永遠(yuǎn)得不到執(zhí)行的機(jī)會。

解決方案:如果需要保證每個線程都有機(jī)會執(zhí)行,可以考慮使用公平模式的Semaphore。

問題三:性能問題

在高并發(fā)場景中,Semaphore可能成為性能瓶頸。由于線程頻繁地獲取和釋放許可,可能會導(dǎo)致過多的上下文切換和競爭。

解決方案:適當(dāng)調(diào)整許可的數(shù)量,或者尋找其他更適合高并發(fā)場景的并發(fā)工具。

代碼示例

讓小黑通過代碼來展示如何妥善處理這些問題:

import java.util.concurrent.Semaphore;

public class SemaphoreProblemSolving {
    private static final Semaphore semaphore = new Semaphore(1);

    public static void main(String[] args) {
        Thread thread1 = new Thread(SemaphoreProblemSolving::safeMethod, "線程1");
        Thread thread2 = new Thread(SemaphoreProblemSolving::safeMethod, "線程2");

        thread1.start();
        thread2.start();
    }

    private static void safeMethod() {
        try {
            semaphore.acquire();
            try {
                // 執(zhí)行關(guān)鍵區(qū)域代碼
                System.out.println(Thread.currentThread().getName() + " 在執(zhí)行");
                Thread.sleep(1000);
            } finally {
                semaphore.release(); // 確??偸轻尫旁S可
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

在這段代碼中,小黑展示了如何使用try-finally塊來確保無論如何都會釋放Semaphore的許可。這種方式可以減少由于異常導(dǎo)致的資源耗盡問題。

第7章:與其他并發(fā)工具的結(jié)合使用

結(jié)合CountDownLatch

CountDownLatch是一種同步幫助,它允許一個或多個線程等待其他線程完成一系列操作。在某些場景中,咱們可能需要先用Semaphore控制資源訪問,然后使用CountDownLatch來同步多個線程的進(jìn)度。

結(jié)合CyclicBarrier

CyclicBarrierCountDownLatch類似,但它允許一組線程相互等待,達(dá)到一個共同的障礙點再繼續(xù)執(zhí)行。這在需要多個線程在某個點同步執(zhí)行的場景中非常有用。結(jié)合Semaphore,可以在達(dá)到共同點之前控制線程對資源的訪問。

代碼示例

讓小黑給咱們展示一個結(jié)合使用Semaphore和CountDownLatch的例子:

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;

public class CombinedSemaphoreCountDownLatch {
    private static final int THREAD_COUNT = 5;
    private static final Semaphore semaphore = new Semaphore(2);
    private static final CountDownLatch latch = new CountDownLatch(THREAD_COUNT);

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < THREAD_COUNT; i++) {
            new Thread(new Worker(i, semaphore, latch)).start();
        }
        latch.await();  // 等待所有線程完成
        System.out.println("所有線程執(zhí)行完畢");
    }

    static class Worker implements Runnable {
        private final int workerNumber;
        private final Semaphore semaphore;
        private final CountDownLatch latch;

        Worker(int workerNumber, Semaphore semaphore, CountDownLatch latch) {
            this.workerNumber = workerNumber;
            this.semaphore = semaphore;
            this.latch = latch;
        }

        @Override
        public void run() {
            try {
                semaphore.acquire();
                System.out.println("工人 " + workerNumber + " 正在工作");
                Thread.sleep(1000); // 模擬工作
                semaphore.release();
                latch.countDown(); // 完成工作,計數(shù)減一
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

在這個例子中,小黑創(chuàng)建了一個包含5個線程的場景。使用Semaphore來控制同時工作的線程數(shù)量,同時使用CountDownLatch來確保所有線程都完成工作后主線程才繼續(xù)執(zhí)行。

第8章:總結(jié)

  • 基本概念:Semaphore是一種基于計數(shù)的同步工具,用于控制同時訪問特定資源的線程數(shù)量。
  • 原理理解:Semaphore的實現(xiàn)依賴于AQS(AbstractQueuedSynchronizer),提供了一種機(jī)制來管理和控制線程的訪問。
  • 實際應(yīng)用:從資源池管理到限流控制,Semaphore在多種場景中都非常有用。
  • 高級特性:包括公平性和非公平性的選擇,以及對線程中斷的響應(yīng)。
  • 問題解決:面對資源耗盡和性能問題,咱們學(xué)習(xí)了如何妥善處理Semaphore帶來的挑戰(zhàn)。
  • 與其他工具結(jié)合:Semaphore能與CountDownLatch、CyclicBarrier等并發(fā)工具結(jié)合使用,解決更復(fù)雜的并發(fā)問題。

到此這篇關(guān)于詳解Java中信號量Semaphore的使用的文章就介紹到這了,更多相關(guān)Java信號量Semaphore內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java中的ArrayList.trimToSize()方法詳解

    Java中的ArrayList.trimToSize()方法詳解

    這篇文章主要介紹了Java中的ArrayList.trimToSize()方法詳解,前幾天看了Java?ArrayList,沒有明白trimToSize()這個方法是什么意思,所以看了一下源碼并且debug一下自己的一個例子,明白了其中的含義,需要的朋友可以參考下
    2023-11-11
  • SpringBoot中如何進(jìn)行全局異常處理方式

    SpringBoot中如何進(jìn)行全局異常處理方式

    在SpringBoot開發(fā)過程中,全局異常處理能提高程序的魯棒性并降低代碼耦合,通過使用@RestControllerAdvice和@ExceptionHandler注解,可以實現(xiàn)對程序異常的全局?jǐn)r截和處理,首先需要自定義一個繼承自ResponseEntityExceptionHandler的異常處理類
    2024-11-11
  • Java使用kafka發(fā)送和生產(chǎn)消息的示例

    Java使用kafka發(fā)送和生產(chǎn)消息的示例

    本篇文章主要介紹了Java使用kafka發(fā)送和生產(chǎn)消息的示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-04-04
  • 詳解Java中的日期類

    詳解Java中的日期類

    這篇文章主要介紹了Java中的日期類的相關(guān)資料,幫助大家更好的利用Java處理時間,感興趣的朋友可以了解下
    2020-10-10
  • 詳解elasticsearch實現(xiàn)基于拼音搜索

    詳解elasticsearch實現(xiàn)基于拼音搜索

    這篇文章主要為大家介紹了詳解elasticsearch實現(xiàn)基于拼音搜索示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • 淺談@mapper引入不到引入的是@MapperScan的問題

    淺談@mapper引入不到引入的是@MapperScan的問題

    這篇文章主要介紹了淺談@mapper引入不到引入的是@MapperScan的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-10-10
  • Java基礎(chǔ)概述面試題復(fù)習(xí)

    Java基礎(chǔ)概述面試題復(fù)習(xí)

    這篇文章主要介紹了java基礎(chǔ)面試題,文中的描述非常詳細(xì),對正在學(xué)習(xí)java基礎(chǔ)的小伙伴們有非常好的幫助,需要的朋友可以參考下,希望能給你帶來幫助
    2021-08-08
  • Java三大特性之封裝詳解

    Java三大特性之封裝詳解

    面向?qū)ο缶幊陶Z言是對客觀世界的模擬,客觀世界里成員變量都是隱藏在對象內(nèi)部的,外界無法直接操作和修改。?封裝可以被認(rèn)為是一個保護(hù)屏障,防止該類的代碼和數(shù)據(jù)被其他類隨意訪問。本文將來和大家詳細(xì)說說Java中的封裝,需要的可以了解一下
    2022-10-10
  • SpringBoot+Vue中的Token續(xù)簽機(jī)制

    SpringBoot+Vue中的Token續(xù)簽機(jī)制

    本文主要介紹了SpringBoot+Vue中的Token續(xù)簽機(jī)制,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-06-06
  • JVM之方法返回地址詳解

    JVM之方法返回地址詳解

    這篇文章主要介紹了JVM之方法返回地址詳解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-02-02

最新評論