Tomcat執行緒模型 BIO模型原始碼與調優
BIO模型:
一個請求建立一個工作執行緒,每個請求都是同步阻塞的,也就是順序訪問完成之後才會給出響應.
其中收到請求分為幾步:1.收到請求,2建立工作執行緒,3.讀取socket請求內容,4.執行業務邏輯,5.寫socket響應.
這幾步都是順序執行的,同步呼叫,阻塞的.意思就是有一個步驟卡頓響應都收不回來.
好處,編碼簡單,
壞處:一個請求一個執行緒,執行緒過多會造成伺服器壓力過大.
一張圖看到Tomcat的BIO
使用者請求到達acceptor 執行緒組, 其中一條執行緒 (acceptor)接收請求,之後會建立工作執行緒,封裝出request,經過過濾器filter,去執行Servlet業務邏輯.之後返回響應.
涉及原始碼
1.Accept執行緒組:
Accept 類 執行緒組 acceptorThreadCount=== 決定了acceptor有多少個執行緒,下面列出建立acceptor執行緒的原始碼.
這裡數量不多,直接用的執行緒,並且把它設定為守護執行緒.
2.Acceptor extends Runnable
建立完成acceptor下面就是每個acceptor如何工作的.看原始碼如下:
執行邏輯:如果達到最大執行緒數,就加入等待佇列進行等待(這裡有個調優的引數acceptCount), 最大執行緒數預設是10000, 下面用工廠方法建立一個socket,本質就是 serverSocket 執行accept( )方法, 如果沒有socket就一直阻塞在這句.再下面就是跑異常或者執行完成,減少執行執行緒計數,之後關閉socket. 真正執行工作執行緒的程式碼是 if(!processSocket(socket)) 這一句程式碼.
3.工作執行緒 SocketProcessor extends Runnable
封裝socket.程式設計wrapper
先判斷是否達到最大時間,到了就強制關閉,
再判斷是否開啟SSH連線
再進行建立工作執行緒,new SocketProcessor(wrapper);
maxThread就是指的這個執行緒數,同時業務邏輯有慢查詢或者夯住了,死鎖了都是引起這個執行緒出問題 .
工作執行緒池就是 getExecutor()獲得的執行緒池.
調優引數
acceptCount === 等待最大佇列
address === 繫結客戶端特定地址,127.0.0.1
bufferSize === 每個請求的緩衝區大小,緩衝區總大小是bufferSize * maxThreads
compression === 是否啟用文件
compressableMimeTypes === text/html,text/xml,text/plain
connectionTimeout === 客戶發起連結 到 服務端接收為止,中間最大的等待時間
connectionUploadTimeout === upload 情況下連線超時時間
disableUploadTimeout === true 則使用connectionTimeout
enableLookups === 禁用DNS查詢 true
keepAliveTimeout === 當長連結閒置 指定時間主動關閉 連結 ,前提是客戶端請 求頭 帶上這個 head”connection” ” keep-alive”
maxKeepAliveRequests === 最大的 長連線數
maxHttpHeaderSize === 最大請求頭大小
maxSpareThreads === BIO 模式下 最多線閒置執行緒數
maxThreads === 最大執行執行緒數 預設是10000
minSpareThreads === BIO 模式下 最小線閒置執行緒數
自己實現簡單的BIO
/**
* 客戶端
*/
public class Client {
private String host ;
private int port ;
private int timeout = 6000;//毫秒
public Client(String host, int port) {
this.host = host;
this.port = port;
}
public void start(){
//建立socket
Socket socket = new Socket();
BufferedWriter bw ;
BufferedReader br ;
try {
//連結伺服器
SocketAddress socketAddress = new InetSocketAddress(host,port);
socket.connect(socketAddress,timeout);
//通過輸出流向伺服器寫入請求
bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
//通過輸入流讀取伺服器響應
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//通過控制檯輸入作為請求輸入
Scanner scanner = new Scanner(System.in);
//迴圈不間斷接收請求輸入
while (true){
System.out.println("等待請求來臨");
String request = scanner.nextLine();
//請求傳送伺服器
bw.write(request);
bw.newLine();//加個換行
bw.flush();//寫入伺服器
System.out.println("訊息已經傳送給伺服器:"+request);
//接收伺服器響應
String response = br.readLine(); //會阻塞在這句程式碼上
System.out.println("收到伺服器響應:"+response);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
服務端
package wow.tomcat.bio;
import wow.tomcat.IServer;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Server implements IServer {
private static final int PORT = 8080;
private int port;
public Server(int port) {
this.port = port;
}
public Server() {
this.port = PORT;
}
public void start(){
try {
ServerSocket serverSocket = new ServerSocket(port);
System.out.println("伺服器啟動");
while (true){
//監聽
System.out.println("開啟監聽");
Socket socket = serverSocket.accept();
//接收請求
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String request = br.readLine();
System.out.println("收到請求:"+request);
//servlet
String response = servletWork(request);
// 響應
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bw.write(response);
bw.newLine();
bw.flush();
System.out.println("返回響應:"+response);
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 這是模擬的邏輯
* @param request
* @return
*/
private String servletWork(String request) {
if("時間".equals(request)) {
return "當前時間是:" + System.currentTimeMillis();
}
return "請輸入正確命令,輸入時間";
}
}
執行緒版的BIO
package wow.tomcat.bio;
import wow.tomcat.IServer;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
*真實的Tomcat中,伺服器還有超時時間,讀超時,寫超時,執行緒超時等.
*/
public class BioServer implements IServer {
private ExecutorService executorService ;
//tomcat原始碼中就是併發10000
private static final int maxThread = 10000;
private int threadNum ;
private int port ;
private static final int PORT =8080 ;
public BioServer(int port,int threadNum) {
this.port = port;
this.executorService = Executors.newFixedThreadPool(threadNum);
}
public BioServer(){
this.port = PORT;
this.executorService = Executors.newFixedThreadPool(maxThread);
}
public void start(){
try {
System.out.println("伺服器啟動");
ServerSocket serverSocket = new ServerSocket(port);
while (true){
Socket socket = serverSocket.accept();
executorService.submit(new WorkThread(socket));
}
} catch (IOException e) {
e.printStackTrace();
}
}
private class WorkThread implements Runnable{
private Socket socket;
public WorkThread(Socket socket) {
this.socket = socket;
}
public void run() {
try {
//接收請求
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String request = br.readLine();
System.out.println("收到請求:"+request);
//servlet
String response = servletWork(request);
// 響應
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bw.write(response);
bw.newLine();
bw.flush();
System.out.println("返回響應:"+response);
}catch (IOException e){
e.printStackTrace();
}finally {
}
}
/**
* 這是模擬的邏輯
* @param request
* @return
*/
private String servletWork(String request) {
if("時間".equals(request)) {
return "當前時間是:" + System.currentTimeMillis();
}
return "請輸入正確命令,輸入時間";
}
}
}
相關文章
- 從聯結器元件看Tomcat的執行緒模型——BIO模式元件Tomcat執行緒模型模式
- 執行緒池執行模型原始碼全解析執行緒模型原始碼
- Dubbo RPC執行緒模型 原始碼分析RPC執行緒模型原始碼
- Netty原始碼解析一——執行緒池模型之執行緒池NioEventLoopGroupNetty原始碼執行緒模型OOP
- 執行緒模型執行緒模型
- Netty原始碼分析之Reactor執行緒模型詳解Netty原始碼React執行緒模型
- (三)Redis 執行緒與IO模型Redis執行緒模型
- tomcat連線處理機制和執行緒模型Tomcat執行緒模型
- Dubbo執行緒模型執行緒模型
- WPF執行緒模型執行緒模型
- redis執行緒模型Redis執行緒模型
- 常用高併發網路執行緒模型設計及mongodb執行緒模型優化實踐執行緒模型MongoDB優化
- Dubbo的執行緒模型執行緒模型
- 程式和執行緒模型執行緒模型
- Redis的執行緒模型Redis執行緒模型
- 03.執行緒模型執行緒模型
- webrtc執行緒模型分析Web執行緒模型
- 從聯結器元件看Tomcat的執行緒模型——NIO模式元件Tomcat執行緒模型模式
- Netty原始碼死磕一(netty執行緒模型及EventLoop機制)Netty原始碼執行緒模型OOP
- 多執行緒之共享模型執行緒模型
- 鴻蒙HarmonyOS實戰-Stage模型(執行緒模型)鴻蒙模型執行緒
- 模型調優模型
- mongodb核心原始碼實現及效能最佳化:常用高併發執行緒模型設計及mongodb執行緒模型最佳化實踐MongoDB原始碼執行緒模型
- 淺談Netty的執行緒模型Netty執行緒模型
- Java 執行緒記憶體模型Java執行緒記憶體模型
- Redis之單執行緒 Reactor 模型Redis執行緒React模型
- Redis執行緒模型的前世今生Redis執行緒模型
- pyspark與py4j執行緒模型簡析Spark執行緒模型
- 常用高併發網路執行緒模型效能優化實現-體驗百萬級高併發執行緒模型設計執行緒模型優化
- Node.js 的單執行緒事件驅動模型和內建的執行緒池模型Node.js執行緒事件模型
- 虛擬執行緒相對於Actor模型或平臺執行緒的主要優勢? - Reddit執行緒模型
- 從聯結器元件看Tomcat的執行緒模型——聯結器簡介元件Tomcat執行緒模型
- [原始碼分析] 分散式任務佇列 Celery 多執行緒模型 之 子程式原始碼分散式佇列執行緒模型
- [Web Server]Tomcat調優之SpringBoot內嵌Tomcat原始碼分析WebServerTomcatSpring Boot原始碼
- 深入學習redis 的執行緒模型Redis執行緒模型
- Java多執行緒記憶體模型Java執行緒記憶體模型
- Redis篇:單執行緒I/O模型Redis執行緒模型
- IO流中「執行緒」模型總結執行緒模型