欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解Java中信號(hào)量Semaphore的使用

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

第1章:引言

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

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

第2章:Semaphore的基本概念

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

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

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

import java.util.concurrent.Semaphore;

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

    public static void main(String[] args) {
        // 創(chuàng)建并啟動(dòng)三個(gè)線程
        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 {
                // 請(qǐng)求許可
                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();
            }
        }
    }
}

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

第3章:Semaphore的核心原理

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

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

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

讓小黑通過(guò)一段代碼來(lái)更好地說(shuō)明這個(gè)原理:

import java.util.concurrent.Semaphore;

public class SemaphoreDeepDive {
    public static void main(String[] args) {
        // 初始化一個(gè)只有2個(gè)許可的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)建并啟動(dòng)3個(gè)線程
        for (int i = 0; i < 3; i++) {
            new Thread(task).start();
        }
    }
}

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

第4章:使用Semaphore的場(chǎng)景

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

場(chǎng)景一:資源池

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

場(chǎng)景二:限流

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

代碼示例

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

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

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

第5章:Semaphore的高級(jí)特性

公平性與非公平性

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

在Java中,創(chuàng)建Semaphore時(shí)可以指定是公平模式還是非公平模式。默認(rèn)情況下,Semaphore是非公平的。公平模式通常會(huì)有更高的性能開(kāi)銷(xiāo),因?yàn)樗枰S護(hù)一個(gè)更加復(fù)雜的內(nèi)部結(jié)構(gòu)來(lái)保證順序。

可中斷操作

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

代碼示例

讓小黑給你演示一下這兩個(gè)特性的代碼實(shí)例:

import java.util.concurrent.Semaphore;

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

        // 創(chuàng)建并啟動(dòng)兩個(gè)線程
        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); // 等待一會(huì)
        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() + " 釋放了許可");
            }
        }
    }
}

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

第6章:Semaphore的問(wèn)題與解決方案

問(wèn)題一:資源耗盡

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

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

問(wèn)題二:公平性問(wèn)題

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

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

問(wèn)題三:性能問(wèn)題

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

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

代碼示例

讓小黑通過(guò)代碼來(lái)展示如何妥善處理這些問(wèn)題:

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塊來(lái)確保無(wú)論如何都會(huì)釋放Semaphore的許可。這種方式可以減少由于異常導(dǎo)致的資源耗盡問(wèn)題。

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

結(jié)合CountDownLatch

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

結(jié)合CyclicBarrier

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

代碼示例

讓小黑給咱們展示一個(gè)結(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(); // 完成工作,計(jì)數(shù)減一
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

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

第8章:總結(jié)

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

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

相關(guān)文章

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

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

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

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

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

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

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

    詳解Java中的日期類(lèi)

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

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

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

    淺談@mapper引入不到引入的是@MapperScan的問(wèn)題

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

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

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

    Java三大特性之封裝詳解

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

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

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

    JVM之方法返回地址詳解

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

最新評(píng)論