spring 使用easypoi進行Excel匯出的簡要操作
阿新 • • 發佈:2021-02-06
Netty
一、Netty介紹和應用場景
1.1 Netty的介紹
Netty
是由JBOSS
提供的一個Java
開源框架,現為Github
Netty
是一個非同步的、基於事件驅動的網路應用框架,用以快速開發高效能、高可靠性的網路IO
程式。Netty
主要針對在TCP
協議下,面向Clients
端的高併發應用,或者Peer-to-Peer
場景下的大量資料持續傳輸的應用。Netty
本質是一個NIO
框架,適用於伺服器通訊相關的多種應用場景。
1.2 Netty的應用場景
1.2.1 網際網路行業
- 網際網路行業:在分散式系統中,各個節點之間需要遠端服務呼叫,高效能的
RPC
框架必不可少,Netty
作為非同步高效能的通訊框架,往往作為基礎通訊元件被這些RPC
框架使用。 - 典型的應用有:阿里分散式服務框架
Dubbo
的RPC
框架使用Dubbo
Dubbo
協議預設使用Netty
作為基礎通訊元件,用於實現各程序節點之間的內部通訊。
1.2.2 遊戲行業
- 無論是手遊服務端還是大型的網路遊戲,Java語言得到了越來越廣泛的應用。
Netty
作為高效能的基礎通訊元件,提供了TCP/UDP
和HTTP
協議棧,方便定製和開發私有協議棧,賬號登入伺服器。- 地圖伺服器之間可以方便的通過
Netty
進行高效能的通訊。
1.2.3 大資料領域
- 經典的
Hadoop
的高效能通訊和序列化元件Avro
的RPC
框架,預設採用Netty
進行跨界點通訊。 - 它的
NettyService
基於Netty
框架二次封裝實現。
三、JavaBIO程式設計
2.1 I/O模型
I/O
模型簡單的理解:就是用什麼樣的通道進行資料的傳送和接收,很大程度上決定了程式通訊的效能。Java
共支援3種網路程式設計模型I/O
模式:BIO
、NIO
、AIO
。JavaBIO
:同步並阻塞(傳統阻塞型),伺服器實現模式為一個連線一個執行緒,即客戶端有連線請求時伺服器端就需要啟動一個執行緒進行處理,如果這個連線不做任何事情會造成不必要的執行緒開銷。
JavaNIO
:同步非阻塞,伺服器實現模式為一個執行緒處理多個請求(連線),即客戶端傳送的連線請求都會註冊到多路複用器上,多路複用器輪詢到連線有I/O
請求就進行處理。
JavaAIO(NIO.2)
:非同步非阻塞,AIO
引入非同步通道的概念,採用了Proactor
模式,簡化了程式編寫,有效的請求才啟動執行緒,它的特點是先由作業系統完成後才通知服務端程式啟動執行緒去處理,一般適用於連線數較多且連線時間較長的應用。
2.2 BIO、NIO、AIO適用場景分析
BIO
方式適用於連線數目比較小且固定的架構,這種方式對伺服器資源要求比較高,併發侷限於應用中,JDK1.4
以前的唯一選擇,但程式簡單易理解。NIO
方式適用於連線數目多且連線比較短(輕操作)的架構,比如聊天伺服器,彈幕系統,伺服器間通訊等。程式設計比較複雜,JDK1.4
開始支援。AIO
方式使用於連線數目多且連線比較長(重操作)的架構,比如相簿伺服器,充分呼叫OS
參與併發操作,程式設計比較複雜,JDK7
開始支援。
2.3 JavaBIO基本介紹
JavaBIO
就是傳統的javaio
程式設計,其相關的類和介面在java.io
。BIO(blockingI/O)
:同步阻塞,伺服器實現模式為一個連線一個執行緒,即客戶端有連線請求時伺服器端就需要啟動一個執行緒進行處理,如果這個連線不做任何事情會造成不必要的執行緒開銷,可以通過執行緒池機制改善(實現多個客戶連線伺服器)。BIO
方式適用於連線數目比較小且固定的架構,這種方式對伺服器資源要求比較高,併發侷限於應用中,JDK1.4
以前的唯一選擇,程式簡單易理解。
2.4 JavaBIO工作機制
- 伺服器端啟動一個
ServerSocket
。 - 客戶端啟動
Socket
對伺服器進行通訊,預設情況下伺服器端需要對每個客戶建立一個執行緒與之通訊。 - 客戶端發出請求後,先諮詢伺服器是否有執行緒響應,如果沒有則會等待,或者被拒絕。
- 如果有響應,客戶端執行緒會等待請求結束後,在繼續執行。
2.5 JavaBIO應用例項
- 使用
BIO
模型編寫一個伺服器端,監聽6666埠,當有客戶端連線時,就啟動一個執行緒與之通訊。 - 要求使用執行緒池機制改善,可以連線多個客戶端。
- 伺服器端可以接收客戶端傳送的資料(
telnet
方式即可)。
public class BIOServer {
public static void main(String[] args) throws Exception {
//1.建立一個執行緒池
//2.如果有客戶端連線,就建立一個執行緒,與之通訊(單獨寫一個方法)
ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
//建立ServerSocket
ServerSocket serverSocket = new ServerSocket(6666);
System.out.println("伺服器啟動了");
while (true) {
System.out.println("執行緒資訊id=" + Thread.currentThread().getId() + "名字=" +
Thread.currentThread().getName());
//監聽,等待客戶端連線
System.out.println("等待連線....");
final Socket socket = serverSocket.accept();
System.out.println("連線到一個客戶端");
//就建立一個執行緒,與之通訊(單獨寫一個方法)
newCachedThreadPool.execute(new Runnable() {
public void run() {
//我們重寫
//可以和客戶端通訊
handler(socket);
}
});
}
}
/**
* 編寫一個handler方法,和客戶端通訊
* @param socket
*/
public static void handler(Socket socket) {
try {
System.out.println("執行緒資訊id=" + Thread.currentThread().getId() + "名字=" +
Thread.currentThread().getName());
byte[] bytes = new byte[1024];
//通過socket獲取輸入流
InputStream inputStream = socket.getInputStream();
//迴圈的讀取客戶端傳送的資料
while (true) {
System.out.println("執行緒資訊id=" + Thread.currentThread().getId() + "名字=" +
Thread.currentThread().getName());
System.out.println("read....");
int read = inputStream.read(bytes);
if (read != -1) {
System.out.println(new String(bytes, 0, read));
//輸出客戶端傳送的資料
} else {
break;
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("關閉和client的連線");
try {
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
//啟動結果
伺服器啟動了
執行緒資訊id=1名字=main
等待連線....
//進入命令列視窗 telnet 127.0.0.1 6666
連線到一個客戶端
執行緒資訊id=1名字=main
等待連線....
執行緒資訊id=12名字=pool-1-thread-1
執行緒資訊id=12名字=pool-1-thread-1
read....
//在客戶端輸入 ctrl+]
//send client1
client1
執行緒資訊id=12名字=pool-1-thread-1
read....
//send client ok
client ok
執行緒資訊id=12名字=pool-1-thread-1
read....
//新開啟一個命令列視窗 telnet 127.0.0.1 6666
連線到一個客戶端
執行緒資訊id=1名字=main
等待連線....
執行緒資訊id=13名字=pool-1-thread-2
執行緒資訊id=13名字=pool-1-thread-2
read....
//在客戶端輸入 ctrl+]
//send client1
client2
執行緒資訊id=13名字=pool-1-thread-2
read....
client2 ok
執行緒資訊id=13名字=pool-1-thread-2
read....
2.6 JavaBIO問題分析
- 每個請求都需要建立獨立的執行緒,與對應的客戶端進行資料
Read
,業務處理,資料Write
。 - 當併發數較大時,需要建立大量執行緒來處理連線,系統資源佔用較大。
- 連線建立後,如果當前執行緒暫時沒有資料可讀,則執行緒就阻塞在
Read
操作上,造成執行緒資源浪費。
三、JavaNIO程式設計
3.1 JavaNIO基本介紹
-
JavaNIO
全稱java non-blockingIO
,是指JDK
提供的新API
。從JDK1.4
開始,Java
提供了一系列改進的輸入/輸出的新特性,被統稱為NIO
(即NewIO
),是同步非阻塞的。 -
NIO
相關類都被放在java.nio
包及子包下,並且對原java.io
包中的很多類進行改寫。 -
NIO
有三大核心部分:Channel
(通道),Buffer
(緩衝區),Selector
(選擇器)。 -
NIO
是面向緩衝區,或者面向塊程式設計的。資料讀取到一個它稍後處理的緩衝區,需要時可在緩衝區中前後移動,這就增加了處理過程中的靈活性,使用它可以提供非阻塞式的高伸縮性網路。 -
JavaNIO
的非阻塞模式,使一個執行緒從某通道傳送請求或者讀取資料,但是它僅能得到目前可用的資料,如果目前沒有資料可用時,就什麼都不會獲取,而不是保持執行緒阻塞,所以直至資料變的可以讀取之前,該執行緒可以繼續做其他的事情。非阻塞寫也是如此,一個執行緒請求寫入一些資料到某通道,但不需要等待它完全寫入,這個執行緒同時可以去做別的事情。 -
通俗理解:
NIO
是可以做到用一個執行緒來處理多個操作的。假設有10000個請求過來,根據實際情況,可以分配50或者100個執行緒來處理。不像之前的阻塞IO
那樣,非得分配10000個。 -
HTTP2.0
使用了多路複用的技術,做到同一個連線併發處理多個請求,而且併發請求的數量比HTTP1.1
大了好幾個數量級。public class BasicBuffer { public static void main(String[] args) { //舉例說明Buffer的使用(簡單說明) //建立一個Buffer,大小為5,即可以存放5個int IntBuffer intBuffer = IntBuffer.allocate(5); //向buffer存放資料 for (int i = 0; i < intBuffer.capacity(); i++) { intBuffer.put(i * 2); } //如何從buffer讀取資料 //將buffer轉換,讀寫切換(!!!) intBuffer.flip(); while (intBuffer.hasRemaining()) { System.out.println(intBuffer.get()); } } } //結果 0 2 4 6 8