Java IO三大模型(BIO/NIO/AIO)的使用總結(jié)
相信很多Java開(kāi)發(fā)剛接觸IO模型時(shí),都會(huì)被「BIO、NIO、AIO」「同步、異步、阻塞、非阻塞」這些概念繞暈,甚至把它們混為一談。其實(shí)IO模型的本質(zhì)很簡(jiǎn)單——就是程序和外部設(shè)備(文件、網(wǎng)絡(luò)、控制臺(tái)等)之間「?jìng)鬏敂?shù)據(jù)的方式」。
今天咱們不聊復(fù)雜的源碼硬啃,而是用「燒水做飯」這個(gè)生活化場(chǎng)景,一步步拆解所有知識(shí)點(diǎn)。
一、先破后立:搞懂IO的核心底層——4個(gè)關(guān)鍵概念(同步/異步、阻塞/非阻塞)
在聊Java IO三大模型之前,必須先分清「同步/異步」和「阻塞/非阻塞」這4個(gè)核心概念——它們是理解所有IO模型的基礎(chǔ),而且兩者完全是不同維度的概念,千萬(wàn)別混為一談!
咱們就用最貼近生活的「燒水做飯」案例,一次性講明白,看完再也不混淆~
1. 同步 vs 異步:兩件事的「執(zhí)行順序」(是否能同時(shí)進(jìn)行)
同步和異步,描述的是「兩件獨(dú)立事情的執(zhí)行關(guān)系」——是串行執(zhí)行(先做A再做B),還是并行執(zhí)行(A和B同時(shí)做),和“等待”無(wú)關(guān),只看順序。
還是以「燒水」和「做飯」(兩件獨(dú)立的事)為例,一看就懂:
- 同步:先把水燒開(kāi),再開(kāi)始做飯(串行執(zhí)行)。只有前一件事(燒水)完全做完,后一件事(做飯)才能啟動(dòng),兩件事不能同時(shí)進(jìn)行。
- 異步:把水壺放在爐子上燒著,同時(shí)就開(kāi)始做飯(并行執(zhí)行)。兩件事互不干擾,不用等前一件事做完,后一件事就能啟動(dòng),最后各自完成即可。
核心記憶點(diǎn):同步是「排隊(duì)做」,異步是「同時(shí)做」。
2. 阻塞 vs 非阻塞:做一件事時(shí)的「自身狀態(tài)」(遇到突發(fā)情況你在干什么)
阻塞和非阻塞,描述的是「做某一件事的過(guò)程中,遇到突發(fā)事件時(shí),你的狀態(tài)是什么」——和“另一件事是什么”無(wú)關(guān),只和你自身的行為有關(guān)。
還是圍繞「燒水做飯」展開(kāi),這次聚焦「做飯這一件事」,遇到「燒水」這個(gè)突發(fā)事件時(shí),你的兩種狀態(tài):
假設(shè)你正在做飯(切菜、洗菜),這是你當(dāng)前唯一的核心任務(wù);突然發(fā)現(xiàn),做飯需要熱水,得去燒一壺水(突發(fā)事件)。此時(shí),你有兩種選擇,對(duì)應(yīng)兩種狀態(tài):
- 阻塞:把水壺放在爐子上后,什么都不做,就站在爐子旁邊盯著水燒開(kāi),期間不切菜、不洗菜——你的核心任務(wù)(做飯)暫停,全程等待突發(fā)事件(燒水)完成,這就是阻塞。
- 非阻塞:把水壺放在爐子上后,不傻等,而是回到廚房繼續(xù)切菜、洗菜(或者玩會(huì)手機(jī)),每隔一會(huì)兒去看看水開(kāi)沒(méi)開(kāi)——你的核心任務(wù)(做飯)沒(méi)有暫停,遇到突發(fā)事件后,你可以做其他事,不用一直等待,這就是非阻塞。
核心記憶點(diǎn):阻塞是「傻等不干活」,非阻塞是「不等先干別的」。
3. 四大組合:用燒水做飯案例,吃透所有組合邏輯
理解了同步/異步(執(zhí)行順序)、阻塞/非阻塞(自身狀態(tài))后,咱們把它們組合起來(lái),還是用「燒水做飯」的案例,逐個(gè)拆解——重點(diǎn)區(qū)分容易混淆的組合,尤其是“異步阻塞”為什么不存在。
(1)同步阻塞:最“笨”的方式(對(duì)應(yīng)BIO)
組合邏輯:同步(做飯必須等燒水完成,串行執(zhí)行)+ 阻塞(燒水時(shí)啥也不做,傻等水開(kāi))。
場(chǎng)景還原:你決定先燒水、再做飯(同步);把水壺放爐子上后,不切菜、不玩手機(jī),就站在旁邊盯著水燒開(kāi),等水完全燒開(kāi)后,才開(kāi)始洗菜、切菜(阻塞)。全程只有一件事在進(jìn)行,效率最低。
(2)同步非阻塞:兼顧“等待”和“效率”(對(duì)應(yīng)NIO)
組合邏輯:同步(做飯必須等燒水完成,串行執(zhí)行)+ 非阻塞(燒水時(shí)不傻等)。
場(chǎng)景還原:你還是要等水燒開(kāi)才能做飯(同步);但把水壺放爐子上后,你不傻等,而是回到廚房切菜、洗菜(或者玩會(huì)手機(jī)),每隔1分鐘去看看水開(kāi)沒(méi)開(kāi)(主動(dòng)檢查),等水開(kāi)后,再切換到做飯的核心步驟(非阻塞)。既沒(méi)有浪費(fèi)時(shí)間,也沒(méi)有忽略突發(fā)事件。
(3)異步非阻塞:最高效的方式(對(duì)應(yīng)AIO)
組合邏輯:異步(燒水和做飯同時(shí)進(jìn)行,并行執(zhí)行)+ 非阻塞(燒水時(shí)不傻等)。
場(chǎng)景還原:你把水壺放爐子上燒著(不用等水開(kāi)),同時(shí)就開(kāi)始洗菜、切菜、做飯(兩件事并行)(異步);期間你該做飯做飯,不用專(zhuān)門(mén)盯著水壺,水開(kāi)后會(huì)發(fā)出“鳴笛聲”通知你(被動(dòng)通知),你聽(tīng)到聲音后,再去關(guān)火、用熱水(非阻塞)。全程兩不耽誤,效率最高。
(4)異步阻塞:邏輯矛盾,不存在的組合
組合邏輯:異步(燒水和做飯同時(shí)進(jìn)行)+ 阻塞(啥也不做,傻等水開(kāi))。
場(chǎng)景還原:你把水壺放爐子上燒著,按理說(shuō)可以同時(shí)做飯(異步),但你卻什么都不做,不做飯、不玩手機(jī),就站在旁邊盯著水燒開(kāi)(阻塞)。這本身就很矛盾——既然選擇了“同時(shí)做兩件事”(異步),又非要“傻等其中一件事”(阻塞),最后和“同步阻塞”沒(méi)區(qū)別,完全浪費(fèi)了異步的優(yōu)勢(shì)。
所以,異步阻塞在實(shí)際場(chǎng)景中完全不存在,也沒(méi)有對(duì)應(yīng)的Java IO模型,咱們不用花時(shí)間糾結(jié)~
二、回歸主題:Java三大IO模型(BIO/NIO/AIO)實(shí)現(xiàn)原理+場(chǎng)景
搞懂了4個(gè)核心概念和組合邏輯,接下來(lái)咱們回歸Java本身——Java中的IO模型,本質(zhì)就是「同步/異步」和「阻塞/非阻塞」的不同組合,對(duì)應(yīng)三大模型:BIO(同步阻塞)、NIO(同步非阻塞)、AIO(異步非阻塞)。
咱們逐個(gè)拆解它們的實(shí)現(xiàn)原理、核心特點(diǎn),結(jié)合前面的案例,讓你一看就懂,還能分清什么時(shí)候用哪個(gè)。
1. BIO:同步阻塞IO(最基礎(chǔ)、最“笨”,新手入門(mén)首選)
(1)核心定位
BIO全稱(chēng)「Blocking IO」,即同步阻塞IO,是Java最早期的IO模型,對(duì)應(yīng)咱們前面說(shuō)的「同步阻塞」組合——程序發(fā)起IO請(qǐng)求后(類(lèi)似燒水),必須等待IO操作(讀/寫(xiě)數(shù)據(jù))完全完成,期間線程會(huì)被掛起,什么都做不了。
(2)實(shí)現(xiàn)原理
BIO的核心是「流(Stream)」,數(shù)據(jù)傳輸是單向的(輸入流讀數(shù)據(jù)、輸出流寫(xiě)數(shù)據(jù)),就像“一根單向的水管”,水只能從一端流到另一端。
實(shí)現(xiàn)邏輯很簡(jiǎn)單:
- 程序(線程)發(fā)起IO請(qǐng)求(比如讀取一個(gè)文件、接收客戶(hù)端連接);
- IO操作未完成時(shí),線程會(huì)被 操作系統(tǒng)掛起(阻塞狀態(tài)),暫停執(zhí)行,期間不能做任何其他任務(wù);
- 直到IO操作完全完成(數(shù)據(jù)讀完、連接建立),線程才會(huì)被喚醒,繼續(xù)執(zhí)行后續(xù)代碼。
(3)核心特點(diǎn)+對(duì)應(yīng)場(chǎng)景
- 優(yōu)點(diǎn):編程簡(jiǎn)單、邏輯直觀,新手容易上手,不用考慮復(fù)雜的輪詢(xún)、回調(diào),直接調(diào)用API就能實(shí)現(xiàn)IO操作。
- 缺點(diǎn):效率極低、資源浪費(fèi)嚴(yán)重。一個(gè)線程只能處理一個(gè)IO請(qǐng)求,高并發(fā)場(chǎng)景下(比如1000個(gè)客戶(hù)端同時(shí)連接),需要?jiǎng)?chuàng)建1000個(gè)線程,線程切換和掛起會(huì)消耗大量系統(tǒng)資源,甚至導(dǎo)致程序崩潰。
- 適用場(chǎng)景:低并發(fā)、簡(jiǎn)單的IO操作,比如本地小文件讀寫(xiě)、簡(jiǎn)單的控制臺(tái)交互,不需要考慮高性能(比如寫(xiě)一個(gè)讀取本地文本文件的小工具)。
(4)簡(jiǎn)單代碼示例(BIO文件讀?。?/h4>
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class BIOExample {
public static void main(String[] args) {
// 讀取本地文件(同步阻塞)
try (BufferedReader br = new BufferedReader(new FileReader("test.txt"))) {
String line;
// readLine() 是阻塞方法:沒(méi)讀到數(shù)據(jù)/文件結(jié)束前,線程會(huì)一直掛起
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class BIOExample {
public static void main(String[] args) {
// 讀取本地文件(同步阻塞)
try (BufferedReader br = new BufferedReader(new FileReader("test.txt"))) {
String line;
// readLine() 是阻塞方法:沒(méi)讀到數(shù)據(jù)/文件結(jié)束前,線程會(huì)一直掛起
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
2. NIO:同步非阻塞IO(高并發(fā)主流,性能提升關(guān)鍵)
(1)核心定位
NIO全稱(chēng)「Non-blocking IO」,即同步非阻塞IO,是JDK 1.4引入的IO模型,對(duì)應(yīng)咱們前面說(shuō)的「同步非阻塞」組合——程序發(fā)起IO請(qǐng)求后,不用等待IO操作完成,線程可以去做其他任務(wù),期間主動(dòng)輪詢(xún)檢查IO操作是否完成。
它解決了BIO高并發(fā)下的資源浪費(fèi)問(wèn)題,是目前Java高并發(fā)網(wǎng)絡(luò)編程的主流(比如Netty框架,就是基于NIO封裝的)。
(2)實(shí)現(xiàn)原理
NIO的核心不再是“流”,而是「通道(Channel)+ 緩沖區(qū)(Buffer)+ 選擇器(Selector)」,三者協(xié)同工作,實(shí)現(xiàn)“單線程處理多個(gè)IO請(qǐng)求”,也就是咱們常說(shuō)的「IO多路復(fù)用」。
拆解三個(gè)核心組件,通俗易懂:
- 通道(Channel):雙向的“水管”,替代BIO的單向流,數(shù)據(jù)可以雙向傳輸(既能讀又能寫(xiě)),比如文件通道(FileChannel)、網(wǎng)絡(luò)通道(SocketChannel)。
- 緩沖區(qū)(Buffer):數(shù)據(jù)的“容器”,所有IO操作都通過(guò)Buffer完成(讀數(shù)據(jù):從通道讀到緩沖區(qū);寫(xiě)數(shù)據(jù):從緩沖區(qū)寫(xiě)到通道),避免頻繁操作底層資源,提升效率。
- 選擇器(Selector):NIO的核心,相當(dāng)于“一個(gè)調(diào)度員”。單線程可以通過(guò)Selector,同時(shí)管理多個(gè)通道,監(jiān)聽(tīng)通道上的IO事件(比如“有數(shù)據(jù)可讀”“有客戶(hù)端連接”);線程不用阻塞等待每個(gè)通道的IO完成,而是由Selector通知線程“哪個(gè)通道的IO準(zhǔn)備好了”,線程再去處理對(duì)應(yīng)的通道。
實(shí)現(xiàn)邏輯總結(jié):
- 創(chuàng)建通道,并設(shè)置為非阻塞模式;
- 將所有通道注冊(cè)到Selector上,指定要監(jiān)聽(tīng)的IO事件;
- 線程通過(guò)Selector輪詢(xún)(非阻塞),檢查是否有通道的IO事件就緒;
- 如果有就緒的通道,線程就去處理對(duì)應(yīng)的IO操作(讀/寫(xiě)數(shù)據(jù));如果沒(méi)有,線程可以去做其他任務(wù),過(guò)會(huì)兒再輪詢(xún)。
(3)核心特點(diǎn)+對(duì)應(yīng)場(chǎng)景
- 優(yōu)點(diǎn):高并發(fā)性能優(yōu)秀,單線程可處理多個(gè)IO請(qǐng)求,減少線程創(chuàng)建和切換的開(kāi)銷(xiāo);資源利用率高,線程不用傻等,可并行處理其他任務(wù)。
- 缺點(diǎn):編程復(fù)雜度比BIO高,需要理解Channel、Buffer、Selector的協(xié)同工作機(jī)制;輪詢(xún)操作會(huì)消耗一定的CPU資源(但比BIO的線程阻塞好得多)。
- 適用場(chǎng)景:高并發(fā)網(wǎng)絡(luò)編程,比如服務(wù)器、網(wǎng)關(guān)、聊天 服務(wù)器等,需要處理大量連接,但每個(gè)連接的數(shù)據(jù)量不大的場(chǎng)景。
(4)簡(jiǎn)單代碼示例(NIO Socket 服務(wù)端,多路復(fù)用)
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class NIOExample {
public static void main(String[] args) throws IOException {
// 1. 創(chuàng)建 ServerSocketChannel 并設(shè)置為非阻塞
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.bind(new InetSocketAddress(8888));
serverChannel.configureBlocking(false); // 關(guān)鍵:設(shè)置非阻塞
// 2. 創(chuàng)建 Selector(選擇器)
Selector selector = Selector.open();
// 3. 將 ServerSocketChannel 注冊(cè)到 Selector,監(jiān)聽(tīng)“連接事件”
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("NIO 服務(wù)端啟動(dòng),監(jiān)聽(tīng)端口:8888");
while (true) {
// 4. 輪詢(xún)就緒的 Channel(阻塞,直到有事件發(fā)生)
selector.select();
// 5. 獲取所有就緒的 SelectionKey
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectedKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove(); // 必須移除,避免重復(fù)處理
// 6. 處理不同事件
if (key.isAcceptable()) {
// 處理連接事件
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel sc = ssc.accept(); // 非阻塞,不會(huì)掛起
sc.configureBlocking(false);
// 注冊(cè)讀事件
sc.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));
System.out.println("客戶(hù)端連接成功:" + sc.getRemoteAddress());
} else if (key.isReadable()) {
// 處理讀事件
SocketChannel sc = (SocketChannel) key.channel();
ByteBuffer buffer = (ByteBuffer) key.attachment();
int read = sc.read(buffer); // 非阻塞,返回讀取的字節(jié)數(shù)
if (read > 0) {
buffer.flip();
String msg = new String(buffer.array(), 0, buffer.limit());
System.out.println("收到客戶(hù)端消息:" + msg);
buffer.clear();
} else if (read < 0) {
// 客戶(hù)端斷開(kāi)連接
sc.close();
key.cancel();
System.out.println("客戶(hù)端斷開(kāi)連接:" + sc.getRemoteAddress());
}
}
}
}
}
}
3. AIO:異步非阻塞IO(高性能天花板,場(chǎng)景受限)
(1)核心定位
AIO全稱(chēng)「Asynchronous IO」,即異步非阻塞IO,是JDK 1.7引入的IO模型(也叫NIO.2),對(duì)應(yīng)咱們前面說(shuō)的「異步非阻塞」組合——程序發(fā)起IO請(qǐng)求后,直接返回,不用等待、不用輪詢(xún),IO操作由操作系統(tǒng)異步完成;當(dāng)IO操作完成后,操作系統(tǒng)會(huì)通過(guò)「回調(diào)函數(shù)」或「Future」通知程序,程序再去處理結(jié)果。
它是三者中效率最高的,但受操作系統(tǒng)支持限制,實(shí)際應(yīng)用不如NIO廣泛。
(2)實(shí)現(xiàn)原理
AIO的核心是「異步回調(diào)」,程序完全不用關(guān)心IO操作的過(guò)程,只需要發(fā)起請(qǐng)求、注冊(cè)回調(diào),剩下的都交給操作系統(tǒng)處理,相當(dāng)于“甩手掌柜”。
實(shí)現(xiàn)邏輯很簡(jiǎn)單,分為3步:
- 程序(線程)發(fā)起IO請(qǐng)求(比如讀取大文件、接收客戶(hù)端連接),并注冊(cè)一個(gè)「回調(diào)函數(shù)」;
- 請(qǐng)求發(fā)起后,線程立即返回,繼續(xù)執(zhí)行其他任務(wù)(非阻塞),IO操作由操作系統(tǒng)在后臺(tái)異步完成;
- 當(dāng)IO操作完成(數(shù)據(jù)讀完、連接建立),操作系統(tǒng)會(huì)自動(dòng)調(diào)用注冊(cè)的回調(diào)函數(shù),通知程序“IO操作完成”,程序再在回調(diào)函數(shù)中處理返回的數(shù)據(jù)。
關(guān)鍵區(qū)別:NIO是「程序主動(dòng)輪詢(xún)」檢查IO是否完成,而AIO是「操作系統(tǒng)被動(dòng)通知」,程序不用做任何等待和輪詢(xún),資源利用率達(dá)到最高。
(3)核心特點(diǎn)+對(duì)應(yīng)場(chǎng)景
- 優(yōu)點(diǎn):性能最優(yōu),全程非阻塞,線程不用等待、不用輪詢(xún),完全解放線程;適合處理大數(shù)據(jù)量、高延遲的IO操作。
- 缺點(diǎn):編程復(fù)雜度最高,需要理解異步回調(diào)、Future等機(jī)制;受操作系統(tǒng)支持限制(Windows系統(tǒng)對(duì)AIO支持較好,Linux系統(tǒng)對(duì)AIO支持有限,實(shí)際開(kāi)發(fā)中常用NIO替代)。
- 適用場(chǎng)景:高并發(fā)、大數(shù)據(jù)量、低延遲的IO場(chǎng)景,比如大文件傳輸、視頻流處理、高性能服務(wù)器等,且操作系統(tǒng)支持異步IO的場(chǎng)景。
(4)簡(jiǎn)單代碼示例(AIO異步回調(diào))
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
public class AIOExample {
public static void main(String[] args) throws IOException {
// 1. 創(chuàng)建異步服務(wù)端通道
AsynchronousServerSocketChannel serverChannel = AsynchronousServerSocketChannel.open();
serverChannel.bind(new InetSocketAddress(8888));
System.out.println("AIO服務(wù)端啟動(dòng),監(jiān)聽(tīng)端口8888...");
// 2. 異步接受連接(注冊(cè)回調(diào)函數(shù),IO完成后自動(dòng)觸發(fā))
serverChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {
@Override
public void completed(AsynchronousSocketChannel sc, Void attachment) {
// 繼續(xù)接受下一個(gè)客戶(hù)端連接(否則只能處理一個(gè)客戶(hù)端)
serverChannel.accept(null, this);
System.out.println("客戶(hù)端連接成功:" + sc);
// 3. 異步讀取客戶(hù)端數(shù)據(jù)(注冊(cè)回調(diào))
ByteBuffer buffer = ByteBuffer.allocate(1024);
sc.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer readBytes, ByteBuffer buf) {
// IO操作完成(讀取到數(shù)據(jù)),處理數(shù)據(jù)
if (readBytes > 0) {
buf.flip();
String msg = new String(buf.array(), 0, readBytes);
System.out.println("收到客戶(hù)端消息:" + msg);
// 繼續(xù)讀取下一次數(shù)據(jù)
sc.read(buf, buf, this);
}
}
@Override
public void failed(Throwable exc, ByteBuffer buf) {
// IO操作失敗,處理異常
exc.printStackTrace();
}
});
}
@Override
public void failed(Throwable exc, Void attachment) {
// 連接失敗,處理異常
exc.printStackTrace();
}
});
// 防止主線程退出(主線程不用處理IO,只負(fù)責(zé)發(fā)起請(qǐng)求)
try {
Thread.currentThread().join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
三、總結(jié):三大IO模型核心對(duì)比(一眼分清,快速選型)
學(xué)到這里,相信你已經(jīng)吃透了Java IO三大模型和核心概念。最后咱們用一張表格,匯總?cè)叩暮诵膮^(qū)別,幫你快速選型,避免踩坑:
| IO模型 | 類(lèi)型 | 核心優(yōu)勢(shì) | 核心劣勢(shì) | 適用場(chǎng)景 |
|---|---|---|---|---|
| BIO | 同步阻塞 | 編程簡(jiǎn)單、邏輯直觀 | 效率低、資源浪費(fèi),不支持高并發(fā) | 低并發(fā)、小文件讀寫(xiě)、簡(jiǎn)單交互 |
| NIO | 同步非阻塞 | 高并發(fā)性能優(yōu)秀,資源利用率高 | 編程復(fù)雜度中等,有輪詢(xún)開(kāi)銷(xiāo) | 高并發(fā)網(wǎng)絡(luò)編程(服務(wù)器、網(wǎng)關(guān)等) |
| AIO | 異步非阻塞 | 性能最優(yōu),完全解放線程 | 編程復(fù)雜,受操作系統(tǒng)支持限制 | 大數(shù)據(jù)量、低延遲場(chǎng)景(大文件傳輸?shù)龋?/td> |
到此這篇關(guān)于Java IO三大模型(BIO/NIO/AIO)的使用總結(jié)的文章就介紹到這了,更多相關(guān)Java IO模型內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
IDEA?2021.3?使用及idea2021.3.1激活使用方法
IDEA?全稱(chēng)?IntelliJ?IDEA,是java語(yǔ)言開(kāi)發(fā)的集成環(huán)境,IntelliJ在業(yè)界被公認(rèn)為最好的java開(kāi)發(fā)工具之一,今天通過(guò)本文給大家介紹idea2021.3.1激活及使用教程,感興趣的朋友一起看看吧2022-01-01
springboot添加多數(shù)據(jù)源的方法實(shí)例教程
這篇文章主要給大家介紹了關(guān)于springboot添加多數(shù)據(jù)源方法的相關(guān)資料,在實(shí)際開(kāi)發(fā)中經(jīng)??赡苡龅皆谝粋€(gè)應(yīng)用中可能要訪問(wèn)多個(gè)數(shù)據(jù)庫(kù)多的情況,需要的朋友可以參考下2023-09-09
MyBatisPlus+SpringBoot實(shí)現(xiàn)樂(lè)觀鎖功能詳細(xì)流程
樂(lè)觀鎖是針對(duì)一些特定問(wèn)題的解決方案,主要解決丟失更新問(wèn)題,下面這篇文章主要給大家介紹了關(guān)于MyBatisPlus+SpringBoot實(shí)現(xiàn)樂(lè)觀鎖功能的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-03-03
java實(shí)現(xiàn)拉鉤網(wǎng)上的FizzBuzzWhizz問(wèn)題示例
這篇文章主要介紹了java實(shí)現(xiàn)拉鉤網(wǎng)上的FizzBuzzWhizz問(wèn)題示例,需要的朋友可以參考下2014-05-05
使用Java servlet實(shí)現(xiàn)自動(dòng)登錄退出功能
這篇文章主要介紹了使用Java servlet實(shí)現(xiàn)自動(dòng)登錄退出功能,,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-11-11

