使用synchronized關(guān)鍵字實(shí)現(xiàn)信號(hào)量的方法
前言
在Java中,信號(hào)量(Semaphore)是一種常用的同步工具,它可以用來(lái)控制對(duì)共享資源的訪(fǎng)問(wèn)數(shù)量。信號(hào)量主要用于兩個(gè)目的:一個(gè)是用于多個(gè)共享資源的互斥使用,另一個(gè)是用于并發(fā)線(xiàn)程數(shù)的控制。雖然Java的java.util.concurrent
包提供了Semaphore
類(lèi),但了解如何手動(dòng)實(shí)現(xiàn)一個(gè)信號(hào)量可以幫助更深入地理解并發(fā)編程的原理。
下面,我們將使用Synchronized
關(guān)鍵字來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的信號(hào)量。我們的目標(biāo)是實(shí)現(xiàn)一個(gè)計(jì)數(shù)信號(hào)量,其中信號(hào)量的計(jì)數(shù)指示可以同時(shí)訪(fǎng)問(wèn)某一資源的線(xiàn)程數(shù)。
實(shí)現(xiàn)基本框架
首先,我們定義一個(gè)Semaphore
類(lèi),它需要維護(hù)一個(gè)計(jì)數(shù)器來(lái)跟蹤可用的許可證數(shù)量。計(jì)數(shù)器的初始值在信號(hào)量創(chuàng)建時(shí)通過(guò)構(gòu)造函數(shù)提供。
public class SimpleSemaphore { private int signals = 0; private int bound = 0; public SimpleSemaphore(int upperBound) { this.bound = upperBound; } }
實(shí)現(xiàn)acquire方法
acquire
方法用于獲取一個(gè)許可。如果當(dāng)前沒(méi)有可用的許可(即signals
等于上界bound
),那么該方法將阻塞,直到有許可可用。
public synchronized void acquire() throws InterruptedException { while (signals == bound) { wait(); } signals++; notify(); }
這里使用synchronized
關(guān)鍵字來(lái)保證方法是線(xiàn)程安全的。如果signals
達(dá)到bound
,調(diào)用wait()
使當(dāng)前線(xiàn)程等待,直到signals
減少后再繼續(xù)執(zhí)行。每次調(diào)用acquire
方法時(shí),signals
都會(huì)增加,并且通過(guò)notify()
喚醒可能在等待的線(xiàn)程。
實(shí)現(xiàn)release方法
release
方法用于釋放一個(gè)許可,增加可用許可的數(shù)量。如果有線(xiàn)程正在等待許可,那么其中一個(gè)線(xiàn)程將被喚醒。
public synchronized void release() throws InterruptedException { while (signals == 0) wait(); signals--; notify(); }
同樣,使用synchronized
確保線(xiàn)程安全,并在釋放許可后通過(guò)notify()
喚醒可能正在等待的線(xiàn)程。
示例使用
以下是如何使用SimpleSemaphore
的一個(gè)簡(jiǎn)單示例。
public class Main { public static void main(String[] args) { SimpleSemaphore semaphore = new SimpleSemaphore(3); // 允許3個(gè)線(xiàn)程同時(shí)訪(fǎng)問(wèn) Runnable longRunningTask = () -> { try { semaphore.acquire(); System.out.println("Thread " + Thread.currentThread().getId() + " is running"); // 模擬長(zhǎng)時(shí)間的任務(wù) Thread.sleep(2000); semaphore.release(); System.out.println("Thread " + Thread.currentThread().getId() + " is finished"); } catch (InterruptedException e) { e.printStackTrace(); } }; for (int i = 0; i < 10; i++) { new Thread(longRunningTask).start(); } } }
在這個(gè)示例中,我們創(chuàng)建了一個(gè)具有3個(gè)許可的SimpleSemaphore
,然后啟動(dòng)了10個(gè)線(xiàn)程來(lái)執(zhí)行一項(xiàng)長(zhǎng)時(shí)間運(yùn)行的任務(wù)。由于信號(hào)量的限制,這10個(gè)線(xiàn)程將分批(每批3個(gè))執(zhí)行。
總結(jié)
通過(guò)使用synchronized
關(guān)鍵字、wait()
和notify()
方法,我們可以手動(dòng)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的信號(hào)量。這個(gè)實(shí)現(xiàn)提供了互斥訪(fǎng)問(wèn)和線(xiàn)程間的協(xié)調(diào)能力。雖然Java的Semaphore
類(lèi)提供了更高級(jí)的功能,但手動(dòng)實(shí)現(xiàn)信號(hào)量是理解并發(fā)控制的一個(gè)很好的練習(xí)。記住,真實(shí)環(huán)境下應(yīng)優(yōu)先使用Java標(biāo)準(zhǔn)庫(kù)中的并發(fā)工具,因?yàn)樗鼈兘?jīng)過(guò)了更廣泛的測(cè)試并且優(yōu)化得更好。
以上就是使用synchronized關(guān)鍵字實(shí)現(xiàn)信號(hào)量的方法的詳細(xì)內(nèi)容,更多關(guān)于synchronized信號(hào)量的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringMVC異常處理知識(shí)點(diǎn)總結(jié)
在本篇文章里小編給大家整理的是關(guān)于SpringMVC異常處理相關(guān)知識(shí)點(diǎn)內(nèi)容,需要的朋友們學(xué)習(xí)下。2019-10-10Java 匿名對(duì)象與匿名內(nèi)部類(lèi)的使用
很多小伙伴對(duì)匿名對(duì)象和匿名內(nèi)部類(lèi)的寫(xiě)法有點(diǎn)陌生,本文主要介紹了Java 匿名對(duì)象與匿名內(nèi)部類(lèi)的使用,具有一定的參考價(jià)值,感興趣的可以了解一下2024-01-01springboot實(shí)現(xiàn)異步調(diào)用@Async的示例
這篇文章主要介紹了springboot實(shí)現(xiàn)異步調(diào)用@Async的示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12java基于JDBC連接Oracle 11g Release2實(shí)例分析
這篇文章主要介紹了java基于JDBC連接Oracle 11g Release2的方法,實(shí)例分析了JDBC連接Oracle 11g Release2容易出現(xiàn)的異常與解決方法,需要的朋友可以參考下2015-06-06java?面向?qū)ο蟠a塊及不同位置對(duì)屬性賦值的執(zhí)行順序
這篇文章主要介紹了java面向?qū)ο蟠a塊及不同位置對(duì)屬性賦值的執(zhí)行順序,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-09-09