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

Java面試最容易被刷的重難點(diǎn)之鎖的使用策略

 更新時(shí)間:2021年10月18日 09:17:57   作者:春風(fēng)~十一載  
鎖像synchronized同步塊一樣,是一種線程同步機(jī)制,但比Java中的synchronized同步塊更復(fù)雜。因?yàn)殒i(以及其它更高級(jí)的線程同步機(jī)制)是由synchronized同步塊的方式實(shí)現(xiàn)的,所以我們還不能完全擺脫synchronized關(guān)鍵字

在多線程的學(xué)習(xí)中,很多時(shí)候都要用到鎖,但我們都知道,加鎖這個(gè)操作是一個(gè)計(jì)算機(jī)中開銷比較大的操作,因此,本篇文章我會(huì)帶大家學(xué)習(xí)在不同場景中進(jìn)行不同的加鎖處理方式,以讓程序更高效一些有關(guān)鎖策略不僅僅局限于某一種語言,在很多語言中都可能會(huì)遇到加鎖操作,而且這部分知識(shí)點(diǎn)也是面試中常見的問題,所以本篇文章內(nèi)容基本都是需要大家自己認(rèn)真理解并做到會(huì)用自己的語言組織起來的。內(nèi)容均為博主認(rèn)真總結(jié),大家可以收藏起來慢慢學(xué)習(xí),希望可以幫到大家哦!

在這里插入圖片描述

一. 樂觀鎖和悲觀鎖

1. 字面理解

樂觀鎖認(rèn)為多個(gè)線程訪問同一個(gè)共享數(shù)據(jù)時(shí)產(chǎn)生并發(fā)沖突的概率不大,并不會(huì)真的加鎖, 而是直接嘗試訪問數(shù)據(jù), 在訪問的同時(shí)識(shí)別當(dāng)前的數(shù)據(jù)是否出現(xiàn)訪問沖突,若沖突,則會(huì)返回當(dāng)前的錯(cuò)誤信息讓用戶去決定如何去處理悲觀鎖會(huì)認(rèn)為多個(gè)線程訪問同一個(gè)共享數(shù)據(jù)時(shí)產(chǎn)生并發(fā)沖突的概率很大,因此往往會(huì)在取數(shù)據(jù)時(shí)會(huì)進(jìn)行加鎖操作,這樣的話其他線程想要拿到這個(gè)數(shù)據(jù)時(shí)就會(huì)阻塞等到直到其他線程獲取到鎖

補(bǔ)充:在Java中synchronized這一加鎖操作主要以悲觀鎖為主,初始使用樂觀鎖策略,但當(dāng)發(fā)現(xiàn)鎖競爭比較頻繁的時(shí)候,就會(huì)自動(dòng)切換成悲觀鎖策略

2. 生活實(shí)例

在生活中有很多情況都能涉及到樂觀和悲觀的心態(tài),比如今天是陰天,A認(rèn)為可能會(huì)下雨,會(huì)提前帶好傘,這就對(duì)應(yīng)到了悲觀鎖這一策略;而B比較樂觀,不會(huì)認(rèn)為會(huì)下雨,因此B不會(huì)帶傘,這顯然可以類比為樂觀鎖這一策略。

在這里插入圖片描述

3. 基于版本號(hào)方式實(shí)現(xiàn)樂觀鎖

實(shí)現(xiàn)樂觀鎖策略這一功能的方式有很多,接下來我?guī)Т蠹胰W(xué)習(xí)一種:基于版本號(hào)方式。
假設(shè)我們要使用多線程修改用戶的賬戶余額,我們可以引入一個(gè)版本號(hào)來實(shí)現(xiàn),具體方法如下:

設(shè)當(dāng)前的余額為100,引入一個(gè)版本號(hào)version,將其初始值設(shè)為1,并且我們規(guī)定,提交版本必須大于數(shù)據(jù)庫中記錄的當(dāng)前版本號(hào)才能執(zhí)行更新余額的操作,若不滿足此條件,則認(rèn)為修改失敗

圖示
以線程1想把主內(nèi)存中的數(shù)據(jù)減50,線程2把主內(nèi)存中的數(shù)據(jù)減20為例:

在這里插入圖片描述

線程1此時(shí)準(zhǔn)備將主內(nèi)存中的數(shù)據(jù)讀入自己的工作內(nèi)存中并修改,而線程2也想將主內(nèi)存的數(shù)據(jù)讀入自己的工作內(nèi)存中并修改,此時(shí)線程1和線程2以及主內(nèi)存中的版本號(hào)都為1

當(dāng)線程1把主內(nèi)存的數(shù)據(jù)減50后,即修改后,會(huì)將自己工作內(nèi)存中的版本號(hào)加1,此時(shí)線程1工作內(nèi)存中的版本號(hào)大于主內(nèi)存中的版本號(hào)(2大于1),因此線程1成功修改了主內(nèi)存中的數(shù)據(jù),并將數(shù)據(jù)50寫入主內(nèi)存中,最后將主內(nèi)存中的版本號(hào)加1(即為2)

在這里插入圖片描述

此時(shí)線程2修改了自己工作內(nèi)存中的數(shù)據(jù),隨后將自己的工作內(nèi)存版本號(hào)改為2:

在這里插入圖片描述

但正當(dāng)線程2準(zhǔn)備將其改好后的數(shù)據(jù)80寫入主內(nèi)存時(shí),發(fā)現(xiàn)自己的版本號(hào)和主內(nèi)存的版本號(hào)都一樣,并不滿足大于關(guān)系,因此此次修改失敗,有效避免了多線程并發(fā)修改數(shù)據(jù)時(shí)引起的數(shù)據(jù)安全問題。
總結(jié)

基于版本號(hào)這樣實(shí)現(xiàn)樂觀鎖的機(jī)制就是一種典型的實(shí)現(xiàn)方式,這個(gè)實(shí)現(xiàn)方式和之前所學(xué)過的單純的互斥的加鎖方式來說更加輕量一些(只修改版本號(hào),只是在計(jì)算機(jī)中用戶態(tài)上進(jìn)行操作,而互斥加鎖方式會(huì)涉及到用戶態(tài)和內(nèi)核態(tài)之間的切換,不僅效率不太高,也容易引起線程阻塞)對(duì)于這個(gè)機(jī)制來說,如果修改數(shù)據(jù)失敗,就會(huì)涉及到重試操作,如果頻繁重試的話那么效率也就不高了,因此,最好在線程并發(fā)沖突率比較低的場景下使用樂觀鎖這一方式比較好

二. 讀寫鎖

1. 理解

在這里插入圖片描述

我們都知道,當(dāng)我們通過多線程方式嘗試修改同一數(shù)據(jù)時(shí),一般都可能引發(fā)線程安全問題,但當(dāng)我們通過多線程方式嘗試讀取同一數(shù)據(jù)時(shí),一般不會(huì)引發(fā)線程安全問題,因此,我們可以根據(jù)讀和寫的不同場景來給讀和寫操作分別加上不同的鎖。
Java當(dāng)中的synchronized不會(huì)對(duì)讀和寫進(jìn)行區(qū)分,默認(rèn)使用后線程都是互斥的

2. 用法

以Java為例,在標(biāo)準(zhǔn)庫中存在這樣一個(gè)類ReentrantReadWriteLock
源代碼如下

public class ReentrantReadWriteLock
        implements ReadWriteLock, java.io.Serializable {
    private static final long serialVersionUID = -6992448646407690164L;
    /** Inner class providing readlock */
    private final ReentrantReadWriteLock.ReadLock readerLock;
    /** Inner class providing writelock */
    private final ReentrantReadWriteLock.WriteLock writerLock;
    /** Performs all synchronization mechanics */
    final Sync sync;

    /**
     * Creates a new {@code ReentrantReadWriteLock} with
     * default (nonfair) ordering properties.
     */
    public ReentrantReadWriteLock() {
        this(false);
    }

該類中提供了兩個(gè)方法:

    public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; }

此方法可以創(chuàng)建出一個(gè)讀鎖實(shí)例

public ReentrantReadWriteLock.ReadLock  readLock()  { return readerLock; }

此方法可以創(chuàng)建出一個(gè)寫鎖實(shí)例
某個(gè)線程被讀鎖修飾后,這兩個(gè)線程之間不會(huì)互斥,而是完全同時(shí)并發(fā)執(zhí)行,一般將讀鎖用于線程讀取數(shù)據(jù)比較多的場景;而當(dāng)某個(gè)線程被寫鎖修飾后,這兩個(gè)線程會(huì)互斥,一個(gè)線程會(huì)執(zhí)行,而另一個(gè)線程會(huì)阻塞等待,因此必須是一個(gè)線程執(zhí)行完了,另一個(gè)線程才會(huì)執(zhí)行,一般用于修改數(shù)據(jù)比較多的場景

三. 重量級(jí)鎖和輕量級(jí)鎖

1. 原理

鎖的核心特性 “原子性”,這樣的機(jī)制追根溯源是 CPU 這樣的硬件設(shè)備提供的

1.CPU 提供了 “原子操作指令”。
2. 操作系統(tǒng)基于 CPU 的原子指令,實(shí)現(xiàn)了 mutex 互斥鎖.
3. JVM 基于操作系統(tǒng)提供的互斥鎖。實(shí)現(xiàn)了 synchronized 和 ReentrantLock 等關(guān)鍵字和類。

在這里插入圖片描述

注意:synchronized 并不僅僅是對(duì) mutex 進(jìn)行封裝, 在 synchronized 內(nèi)部還做了很多其他的工作

2. 理解

1.重量級(jí)鎖依賴了OS提供的mutex,的開銷一般很大,往往是通過內(nèi)核來完成的
2.輕量級(jí)加鎖一般不使用mutex,開銷一般比較小,一般通過用戶態(tài)就能直接完成

3. 區(qū)分用戶態(tài)和內(nèi)核態(tài)

我們可以類比一個(gè)生活中的例子,當(dāng)去銀行辦理業(yè)務(wù)時(shí),如果是通過用戶在銀行工作人員的指導(dǎo)下自己在窗口外完成,那么效率會(huì)比較高,就像計(jì)算機(jī)中的用戶態(tài)一樣。而當(dāng)我們把自己的業(yè)務(wù)交給銀行相關(guān)人員去完成時(shí),由于銀行工作人員的閑忙時(shí)間是不可控的,因此無法保證效率,就好比計(jì)算機(jī)中的內(nèi)核態(tài)。

四. 自旋鎖

1. 理解

當(dāng)兩個(gè)線程為了完成任務(wù)同時(shí)競爭一把鎖時(shí), 拿到鎖的那個(gè)線程會(huì)立馬執(zhí)行任務(wù),而沒拿到就會(huì)阻塞等待,當(dāng)一個(gè)線程把鎖釋放后,另一個(gè)線程不會(huì)被立即喚醒,而是等操作系統(tǒng)將其進(jìn)行一系列的調(diào)度到CPU中的操作才能被喚醒然后執(zhí)行任務(wù),這種鎖叫做掛起等待鎖,線程在搶鎖失敗后進(jìn)入阻塞狀態(tài),放棄 CPU,需要過很久才能再次被調(diào)度。但實(shí)際上,大部分情況下,雖然當(dāng)前搶鎖失敗,但過不了很久,鎖就會(huì)被釋放,所以沒必要就放棄 CPU。這個(gè)時(shí)候就可以使用自旋鎖來處理這樣的問題。

2. 實(shí)現(xiàn)方式

自旋鎖的偽代碼為:while (搶鎖(lock) == 失敗) {}

如果獲取鎖失敗,就會(huì)立即再嘗試獲取鎖,無限循環(huán),直到獲取到鎖為止。第一次獲取鎖失敗, 第二次的嘗試會(huì)在非常短的時(shí)間內(nèi)到來,一旦鎖被其他線程釋放, 就能第一時(shí)間獲取到鎖

3. 優(yōu)缺點(diǎn)

自旋鎖是一種典型的輕量級(jí)鎖的實(shí)現(xiàn)方式,它沒有放棄 CPU, 不涉及線程阻塞和調(diào)度,一旦鎖被釋放,就能第一時(shí)間獲取到鎖,這樣會(huì)大大提高代碼的執(zhí)行效率,但如果鎖被其他線程持有的時(shí)間比較久, 那么就會(huì)持續(xù)地消耗 CPU 資源。(而掛起等待的時(shí)候是不消耗 CPU 的)
因此,我們應(yīng)該注意自旋鎖的適用場合:

  • 如果多個(gè)線程執(zhí)行任務(wù)時(shí)鎖的沖突比較低,或者線程持有鎖的時(shí)間比較短,此時(shí)使用自旋鎖比較合適
  • 如果某個(gè)線程任務(wù)對(duì)CPU比較敏感,且不希望吃太多CPU資源,那么此時(shí)就不太適合使用自旋鎖。

注意:synchronized自身已經(jīng)設(shè)置好了自旋鎖和掛起等待鎖,會(huì)根據(jù)不同的情況自動(dòng)選擇最優(yōu)的使用方案

五. 公平鎖和非公平鎖

1. 理解

若有三個(gè)線程 A,B,C。
A先嘗試獲取鎖,獲取成功了,因?yàn)橹挥幸话焰i,所以B和C線程都會(huì)阻塞等待,那么如果A用完了鎖后,B和C線程哪一個(gè)會(huì)最先獲取到鎖呢?

  • 公平鎖:遵守先來后到原則,因?yàn)锽線程比C線程來的早一點(diǎn),所以B線程先獲取到鎖
  • 非公平鎖:沒有先來后到原則,B和C線程獲取到鎖的概率是隨機(jī)的

2. 注意事項(xiàng)

操作系統(tǒng)內(nèi)部的線程調(diào)度就可以視為是隨機(jī)的,如果不做任何額外的限制,鎖就是非公平鎖。如果要想實(shí)現(xiàn)公平鎖,就需要依賴額外的數(shù)據(jù)結(jié)構(gòu)(比如隊(duì)列) 來記錄線程們的先后順序。公平鎖和非公平鎖沒有好壞之分, 關(guān)鍵還是看適用場景(大部分情況下非公平鎖就夠用了,但當(dāng)我們希望線程的調(diào)度時(shí)間成本是可控的,那么此時(shí)就需要用到公平鎖了)

注意:synchronized為非公平鎖

六. 可重入鎖和不可重入鎖

1. 為什么要引入這兩把鎖

(1)實(shí)例一

在介紹可重入鎖和不可重入鎖之前,大家先來思考一個(gè)問題,為什么Java中的main函數(shù)要用static來修飾?

public class Test {
    public static void main(String[] args) {
        
    }
}

試想以下,如果main函數(shù)不是static來修飾的話:

public class Test {
    public void main(String[] args) {
        Test a=new Test();
        a.main();
    }
}

那么此時(shí)這段代碼能否被執(zhí)行呢?答案是不能,因?yàn)樵趈ava中,沒有static的變量或函數(shù),如果想被調(diào)用的話,是要先新建一個(gè)對(duì)象才可以。而main函數(shù)作為程序的入口,需要在其它函數(shù)實(shí)例化之前就啟動(dòng),這也就是為什么要加一個(gè)static。main函數(shù)好比一個(gè)門,要探索其它函數(shù)要先從門進(jìn)入程序。static提供了這樣一個(gè)特性,無需建立對(duì)象,就可以啟動(dòng)。也可以利用反證法說明,如果不是static修飾的,若不是靜態(tài)的,main函數(shù)調(diào)用的時(shí)候需要new對(duì)象,new完對(duì)象才能調(diào)用main函數(shù)。那么你既想進(jìn)入到main函數(shù)new對(duì)象,又想new完對(duì)象來調(diào)用main函數(shù),那么就不行了,相當(dāng)于自己把自己鎖在里面出不來了

(2)實(shí)例二

另外一個(gè)Java當(dāng)中的例子:

 synchronized void func1(){
        func2();
    }
    synchronized void func2(){
        
    }

我們對(duì)func1這個(gè)方法進(jìn)行加鎖時(shí),是可以成功的,但當(dāng)我們對(duì)func2這個(gè)方法再次加鎖后,就比較危險(xiǎn)了。因?yàn)橐獔?zhí)行完func1這個(gè)方法,就必須執(zhí)行完func2,而此時(shí)鎖已經(jīng)被func1這個(gè)方法占用了,func2獲取不到鎖,所以func2就會(huì)一直阻塞等待,去等func1釋放鎖,但func1一直執(zhí)行不完成,所以鎖永遠(yuǎn)不會(huì)釋放,func2永遠(yuǎn)也獲取不到鎖,這樣就形成了一個(gè)閉環(huán),相當(dāng)于自己把自己鎖在里面出不來了,此時(shí)這個(gè)線程就會(huì)崩潰,是比較危險(xiǎn)的

2. 實(shí)現(xiàn)方案

了解了上面兩個(gè)實(shí)例的嚴(yán)重性后,我們引入了可重入鎖這個(gè)機(jī)制,當(dāng)我們形成死鎖后,如果是可重入鎖的話,它不會(huì)讓線程阻塞等待最終死鎖從而奔潰,而是運(yùn)用計(jì)數(shù)器的方法,去記錄當(dāng)前某個(gè)線程針對(duì)某把鎖嘗試加了幾次,每加一次鎖計(jì)數(shù)都會(huì)加1,每次解鎖計(jì)數(shù)都會(huì)減1,這樣當(dāng)計(jì)數(shù)器里面的計(jì)數(shù)完全為0的時(shí)候才會(huì)真正釋放鎖,正是因?yàn)橛辛诉@樣的機(jī)制,才有效避免了死鎖問題。而在Java中,synchronized就是一把可重入鎖,它給我們提供了很大的方便,保證在我們即使造成死鎖問題時(shí),程序也不至于崩潰。

七. 面試題

第一題

如何理解樂觀鎖和悲觀鎖,具體實(shí)現(xiàn)方式如何 如何理解?

見樂觀鎖和悲觀鎖字面理解部分(嘗試用自己的語言組織)實(shí)現(xiàn)方式:
(1)樂觀鎖:見基于版本號(hào)方式實(shí)現(xiàn)樂觀鎖部分
(2)悲觀鎖:多個(gè)線程訪問同一個(gè)共享數(shù)據(jù)時(shí)產(chǎn)生并發(fā)沖突時(shí),會(huì)在取數(shù)據(jù)時(shí)會(huì)進(jìn)行加鎖操作,這樣的話其他線程想要拿到這個(gè)數(shù)據(jù)時(shí)就會(huì)阻塞等到直到其他線程獲取到鎖

第二題

簡單介紹一下讀寫鎖

讀寫鎖實(shí)際是一種特殊的自旋鎖,它能把同一塊共享數(shù)據(jù)的訪問者分為讀者和寫者,讀寫鎖會(huì)把讀操作和寫操作分別進(jìn)行加鎖,且讀鎖和讀鎖之間的線程不會(huì)發(fā)生互斥,寫鎖和寫鎖之間以及讀鎖和寫鎖之間的線程會(huì)發(fā)生互斥。讀鎖適用于線程讀取數(shù)據(jù)比較多的場景,而寫鎖適用于線程修改數(shù)據(jù)比較多的場景。

第三題

簡單介紹一下自旋鎖

  • 理解:當(dāng)兩個(gè)線程為了完成任務(wù)同時(shí)競爭一把鎖時(shí), 拿到鎖的那個(gè)線程會(huì)立馬執(zhí)行任務(wù),而沒拿到鎖的線程就會(huì)立即再嘗試獲取鎖,無限循環(huán),直到獲取到鎖為止,這樣的鎖就叫自旋鎖
  • 優(yōu)點(diǎn)和缺點(diǎn):見自旋鎖優(yōu)缺點(diǎn)部分

第四題

簡單介紹一下Java中synchronized充當(dāng)了哪些鎖

  • 主要以悲觀鎖為主,初始使用樂觀鎖策略,但當(dāng)發(fā)現(xiàn)鎖競爭比較頻繁的時(shí)候,就會(huì)自動(dòng)切換成悲觀鎖策略
  • 并不區(qū)分讀寫鎖
  • synchronized自身已經(jīng)設(shè)置好了自旋鎖和掛起等待鎖,會(huì)根據(jù)不同的情況自動(dòng)選擇最優(yōu)的使用方案
  • synchronized是一把非公平鎖
  • synchronized就是一把可重入鎖

到此這篇關(guān)于Java面試最容易被刷的重難點(diǎn)之鎖的使用策略的文章就介紹到這了,更多相關(guān)Java 鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java 獲取當(dāng)前時(shí)間的三種方法

    java 獲取當(dāng)前時(shí)間的三種方法

    這篇文章主要介紹了java 獲取當(dāng)前時(shí)間的三種方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-09-09
  • Java編程—在測試中考慮多態(tài)

    Java編程—在測試中考慮多態(tài)

    這篇文章主要介紹了Java編程—在測試中考慮多態(tài),具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-11-11
  • SpringBoot 之啟動(dòng)流程詳解

    SpringBoot 之啟動(dòng)流程詳解

    SpringBoot 是一個(gè)基于 Spring 框架的快速開發(fā)框架,旨在簡化 Spring 應(yīng)用程序的開發(fā)和部署。在本文中,我們將深入分析 SpringBoot 啟動(dòng)過程的源代碼,并提供必要的解釋和說明
    2023-04-04
  • java中關(guān)于文本文件的讀寫方法實(shí)例總結(jié)

    java中關(guān)于文本文件的讀寫方法實(shí)例總結(jié)

    這篇文章主要介紹了java中關(guān)于文本文件的讀寫方法,實(shí)例總結(jié)了Java針對(duì)文本文件讀寫的幾種常用方法,并對(duì)比了各個(gè)方法的優(yōu)劣及特點(diǎn),具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-11-11
  • java String的深入理解

    java String的深入理解

    這篇文章主要介紹了java String的深入理解的相關(guān)資料,希望通過本文大家能理解String的用法,需要的朋友可以參考下
    2017-09-09
  • 關(guān)于Http持久連接和HttpClient連接池的深入理解

    關(guān)于Http持久連接和HttpClient連接池的深入理解

    眾所周知,httpclient是java開發(fā)中非常常見的一種訪問網(wǎng)絡(luò)資源的方式了,下面這篇文章主要給大家介紹了關(guān)于Http持久連接和HttpClient連接池的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-05-05
  • 淺析Java設(shè)計(jì)模式編程中的單例模式和簡單工廠模式

    淺析Java設(shè)計(jì)模式編程中的單例模式和簡單工廠模式

    這篇文章主要介紹了淺析Java設(shè)計(jì)模式編程中的單例模式和簡單工廠模式,使用設(shè)計(jì)模式編寫代碼有利于團(tuán)隊(duì)協(xié)作時(shí)程序的維護(hù),需要的朋友可以參考下
    2016-01-01
  • Java基于動(dòng)態(tài)規(guī)劃法實(shí)現(xiàn)求最長公共子序列及最長公共子字符串示例

    Java基于動(dòng)態(tài)規(guī)劃法實(shí)現(xiàn)求最長公共子序列及最長公共子字符串示例

    這篇文章主要介紹了Java基于動(dòng)態(tài)規(guī)劃法實(shí)現(xiàn)求最長公共子序列及最長公共子字符串,簡單描述了動(dòng)態(tài)規(guī)劃法的概念、原理,并結(jié)合實(shí)例形式分析了Java使用動(dòng)態(tài)規(guī)劃法求最長公共子序列以及最長公共子字符串相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2018-08-08
  • 詳解MyBatis-Plus updateById方法更新不了空字符串/null解決方法

    詳解MyBatis-Plus updateById方法更新不了空字符串/null解決方法

    這篇文章主要介紹了詳解MyBatis-Plus updateById方法更新不了空字符串/null解決方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • 深入理解Java設(shè)計(jì)模式之抽象工廠模式

    深入理解Java設(shè)計(jì)模式之抽象工廠模式

    這篇文章主要介紹了JAVA設(shè)計(jì)模式之抽象工廠模式的的相關(guān)資料,文中示例代碼非常詳細(xì),供大家參考和學(xué)習(xí),感興趣的朋友可以了解下
    2021-11-11

最新評(píng)論