當(dāng)下Java并發(fā)編程日益普及,而Semaphore是Java提供的一種功能強(qiáng)大的線程同步工具,可用于控制同時(shí)訪問系統(tǒng)資源的線程數(shù)量。本篇博客將從Semaphore的簡介、底層實(shí)現(xiàn)和應(yīng)用場景等角度,深入探討Semaphore的原理以及其實(shí)現(xiàn)和使用方法。
## 1、Semaphore的簡介
Semaphore是一種計(jì)數(shù)器,用于控制同時(shí)訪問資源的線程數(shù)量。它通過一個(gè)計(jì)數(shù)器來表達(dá)可用資源的數(shù)量,當(dāng)有新線程需要訪問該資源時(shí),會(huì)先進(jìn)行請求,然后進(jìn)行P(proberen)操作,如果此時(shí)計(jì)數(shù)器的值為0,則線程就會(huì)被阻塞并進(jìn)入等待隊(duì)列中,等到其他線程釋放資源后才重新獲得控制權(quán)。而當(dāng)線程釋放資源時(shí),則會(huì)進(jìn)行V(verhogen)操作,將計(jì)數(shù)器的值加1,以通知其他線程可以繼續(xù)請求訪問資源。
Semaphore的構(gòu)造方法有兩個(gè)參數(shù),分別表示初始的資源數(shù)量和是否為公平鎖。如果將公平鎖設(shè)置為true,則多個(gè)線程并發(fā)訪問Semaphore時(shí),會(huì)按照它們的請求順序進(jìn)行處理,即先請求的線程也會(huì)先獲得資源。
Semaphore是一個(gè)典型的Java并發(fā)庫類,位于java.util.concurrent包中。
## 2、Semaphore的底層實(shí)現(xiàn)
在Semaphore的底層實(shí)現(xiàn)中,它是基于AQS(AbstractQueuedSynchronizer)的同步器實(shí)現(xiàn)的。AQS是一個(gè)為JDK提供的一個(gè)框架,用于實(shí)現(xiàn)同步器,比如鎖、Semaphore等,是基于隊(duì)列的鎖和同步器的實(shí)現(xiàn)框架。
Semaphore的底層實(shí)現(xiàn)主要基于兩個(gè)方法:
- acquire():申請?jiān)S可證,實(shí)際上就是P操作。
- release():釋放許可證,實(shí)際上就是V操作。
在Semaphore的實(shí)現(xiàn)中,如果許可證數(shù)量大于0,則線程可以直接獲取許可證資源并執(zhí)行任務(wù)。如果許可證數(shù)量小于等于0,則線程會(huì)被阻塞,直到其他線程釋放許可證資源,則當(dāng)前線程才能重新獲取許可證并執(zhí)行任務(wù)。需要注意的是,一旦線程獲取到許可證資源,則許可證數(shù)量就會(huì)減1。同理,每次釋放許可證資源,許可證數(shù)量就會(huì)加1。
## 3、Semaphore的應(yīng)用場景
Semaphore的應(yīng)用場景較為廣泛,主要用于控制并發(fā)數(shù)量,防止線程阻塞和死鎖等問題。下面列舉一些Semaphore的應(yīng)用場景和示例代碼:
### 場景1:限流器
Semaphore可用于實(shí)現(xiàn)限流器,即限制同時(shí)訪問某個(gè)資源的線程數(shù)量。比如,我們可以使用Semaphore控制某個(gè)接口的并發(fā)數(shù)量,防止服務(wù)被過度訪問而崩潰。下面是示例代碼:
```
public class RateLimit {
? private Semaphore semaphore;
? public RateLimit(int permits) {
? ? this.semaphore = new Semaphore(permits);
? }
? public void acquire() {
? ? semaphore.acquire();
? }
? public void release() {
? ? semaphore.release();
? }
}
```
### 場景2:數(shù)據(jù)庫連接池
Semaphore可用于實(shí)現(xiàn)數(shù)據(jù)庫連接池,即限制同時(shí)連接數(shù)據(jù)庫的線程數(shù)量。比如,我們可以使用Semaphore來限制連接數(shù),防止數(shù)據(jù)庫過度加載而崩潰。下面是示例代碼:
```
public class DBConnectionPool {
? private final Semaphore semaphore;
? private final List<Connection> pool;
? public DBConnectionPool(int permits, List<Connection> pool) {
? ? this.semaphore = new Semaphore(permits, true);
? ? this.pool = pool;
? }
? public Connection acquire() throws InterruptedException {
? ? semaphore.acquire();
? ? return pool.remove(0);
? }
? public void release(Connection conn) {
? ? pool.add(conn);
? ? semaphore.release();
? }
}
```
### 場景3:線程池
Semaphore可用于實(shí)現(xiàn)線程池,即限制同時(shí)執(zhí)行任務(wù)的線程數(shù)量。比如,我們可以使用Semaphore來控制線程池的大小,防止同時(shí)執(zhí)行太多的任務(wù)而導(dǎo)致系統(tǒng)崩潰。下面是示例代碼:
```
public class MyThreadPool {
? private final Semaphore semaphore;
? private final ExecutorService executor;
? public MyThreadPool(int permits, ExecutorService executor) {
? ? this.semaphore = new Semaphore(permits);
? ? this.executor = executor;
? }
? public void execute(Runnable task) throws InterruptedException {
? ? semaphore.acquire();
? ? executor.execute(() -> {
? ? ? try {
? ? ? ? task.run();
? ? ? } finally {
? ? ? ? semaphore.release();
? ? ? }
? ? });
? }
}
```
## 4、Semaphore的示例代碼
下面給出一個(gè)基于Semaphore實(shí)現(xiàn)的生產(chǎn)者-消費(fèi)者模型的示例代碼,具體實(shí)現(xiàn)可以參考如下:
```
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.Semaphore;
class QueueBuffer<T> {
? Queue<T> buffer = new LinkedList<>();
? Semaphore producerSemaphore = new Semaphore(1);
? Semaphore consumerSemaphore = new Semaphore(0);
? int maxBufferSize = 10;
? public void put(T obj) throws InterruptedException {
? ? producerSemaphore.acquire();
? ? try {
? ? ? while (buffer.size() == maxBufferSize) {
? ? ? ? consumerSemaphore.release();
? ? ? ? producerSemaphore.acquire();
? ? ? }
? ? ? buffer.add(obj);
? ? ? System.out.println(Thread.currentThread().getName() + " put: " + obj);
? ? ? consumerSemaphore.release();
? ? } finally {
? ? ? producerSemaphore.release();
? ? }
? }
? public T get() throws InterruptedException {
? ? consumerSemaphore.acquire();
? ? try {
? ? ? while (buffer.isEmpty()) {
? ? ? ? producerSemaphore.release();
? ? ? ? consumerSemaphore.acquire();
? ? ? }
? ? ? T obj = buffer.poll();
? ? ? System.out.println(Thread.currentThread().getName() + " get: " + obj);
? ? ? producerSemaphore.release();
? ? ? return obj;
? ? } finally {
? ? ? consumerSemaphore.release();
? ? }
? }
}
public class ProducerConsumer {
? public static void main(String[] args) throws InterruptedException {
? ? QueueBuffer<Integer> buffer = new QueueBuffer<>();
? ? Thread producer1 = new Thread(() -> {
? ? ? try {
? ? ? ? for (int i = 1; i <= 10; i++) {
? ? ? ? ? buffer.put(i);
? ? ? ? ? Thread.sleep(1000);
? ? ? ? }
? ? ? } catch (InterruptedException e) {
? ? ? ? e.printStackTrace();
? ? ? }
? ? }, "Producer1");
? ? Thread producer2 = new Thread(() -> {
? ? ? try {
? ? ? ? for (int i = 11; i <= 20; i++) {
? ? ? ? ? buffer.put(i);
? ? ? ? ? Thread.sleep(1000);
? ? ? ? }
? ? ? } catch (InterruptedException e) {
? ? ? ? e.printStackTrace();
? ? ? }
? ? }, "Producer2");
? ? Thread consumer1 = new Thread(() -> {
? ? ? try {
? ? ? ? for (int i = 1; i <= 5; i++) {
? ? ? ? ? buffer.get();
? ? ? ? ? Thread.sleep(2000);
? ? ? ? }
? ? ? } catch (InterruptedException e) {
? ? ? ? e.printStackTrace();
? ? ? }
? ? }, "Consumer1");
? ? Thread consumer2 = new Thread(() -> {
? ? ? try {
? ? ? ? for (int i = 6; i <= 10; i++) {
? ? ? ? ? buffer.get();
? ? ? ? ? Thread.sleep(2000);
? ? ? ? }
? ? ? } catch (InterruptedException e) {
? ? ? ? e.printStackTrace();
? ? ? }
? ? }, "Consumer2");
? ? producer1.start();
? ? producer2.start();
? ? consumer1.start();
? ? consumer2.start();
? ? producer1.join();
? ? producer2.join();
? ? consumer1.join();
? ? consumer2.join();
? }
}
```
以上代碼基于Semaphore實(shí)現(xiàn)了一個(gè)生產(chǎn)者-消費(fèi)者模型,并且內(nèi)置了兩個(gè)生產(chǎn)者和兩個(gè)消費(fèi)者線程,其中生產(chǎn)者會(huì)生產(chǎn)1-20的數(shù)字,并將其放入緩沖區(qū)中,而消費(fèi)者會(huì)從緩沖區(qū)中取出數(shù)據(jù)并進(jìn)行處理(這里采用簡單的輸出操作)。而Semaphore則用于控制兩個(gè)生產(chǎn)者之間的并發(fā)數(shù)量和兩個(gè)消費(fèi)者之間的并發(fā)數(shù)量,以確保線程安全性和程序的正確性。文章來源:http://www.zghlxwxcb.cn/news/detail-451099.html
## 結(jié)語
Semaphore是Java中一個(gè)非常實(shí)用的線程同步工具,可以幫助開發(fā)者控制并發(fā)訪問數(shù)量、防止線程阻塞和死鎖等問題,在多種場景下都有著廣泛的應(yīng)用。本文中介紹了Semaphore的簡介、底層實(shí)現(xiàn)和應(yīng)用場景,同時(shí)演示了Semaphore在生產(chǎn)消費(fèi)模型中的實(shí)現(xiàn)方式,相信讀者可以通過本文進(jìn)一步熟悉Semaphore的使用方法,從而提高對Java并發(fā)編程的理解和實(shí)踐能力。文章來源地址http://www.zghlxwxcb.cn/news/detail-451099.html
到了這里,關(guān)于java并發(fā)-Semaphore的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!