摘要:于是提供了機(jī)制,使得從中讀往里寫變成異步動作。這是因為客戶端的數(shù)據(jù)推送速度太慢了,容器先將收回,當(dāng)容器發(fā)現(xiàn)可以讀取到新數(shù)據(jù)的時候,再分配一個去讀,如此循環(huán)直到全部讀完為止。注意和不能同時使用。
Github地址
相關(guān)系列文章:
Servlet 3.0 異步處理詳解
Spring MVC異步處理的幾種方式
Servlet Async Processing提供了一種異步請求處理的手段(見我的另一篇文章Servlet 3.0 異步處理詳解),能夠讓你將Http thread從慢速處理中釋放出來出來其他請求,提高系統(tǒng)的響應(yīng)度。
但是光有Async Processing是不夠的,因為整個請求-響應(yīng)過程的速度快慢還牽涉到了客戶端的網(wǎng)絡(luò)情況,如果客戶端網(wǎng)絡(luò)情況糟糕,其上傳和下載速度都很慢,那么同樣也會長時間占用Http Thread使其不能被釋放出來。
于是Servlet 3.1提供了Async IO機(jī)制,使得從Request中讀、往Response里寫變成異步動作。
Async Read我們先來一段客戶端上傳速度慢的例子,AsyncReadServlet.java:
@WebServlet(value = "/async-read", asyncSupported = true) public class AsyncReadServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("Servlet thread: " + Thread.currentThread().getName()); AsyncContext asyncCtx = req.startAsync(); ServletInputStream is = req.getInputStream(); is.setReadListener(new ReadListener() { private int totalReadBytes = 0; @Override public void onDataAvailable() { System.out.println("ReadListener thread: " + Thread.currentThread().getName()); try { byte buffer[] = new byte[1 * 1024]; int readBytes = 0; while (is.isReady() && !is.isFinished()) { int length = is.read(buffer); if (length == -1 && is.isFinished()) { asyncCtx.complete(); System.out.println("Read: " + readBytes + " bytes"); System.out.println("Total Read: " + totalReadBytes + " bytes"); return; } readBytes += length; totalReadBytes += length; } System.out.println("Read: " + readBytes + " bytes"); } catch (IOException ex) { ex.printStackTrace(); asyncCtx.complete(); } } @Override public void onAllDataRead() { try { System.out.println("Total Read: " + totalReadBytes + " bytes"); asyncCtx.getResponse().getWriter().println("Finished"); } catch (IOException ex) { ex.printStackTrace(); } asyncCtx.complete(); } @Override public void onError(Throwable t) { System.out.println(ExceptionUtils.getStackTrace(t)); asyncCtx.complete(); } }); } }
我們利用curl的--limit-rate選項來模擬慢速上傳curl -X POST -F "bigfile=@src/main/resources/bigfile" --limit-rate 5k http://localhost:8080/async-read
然后觀察服務(wù)端的打印輸出:
Servlet thread: http-nio-8080-exec-3 ReadListener thread: http-nio-8080-exec-3 Read: 16538 bytes ReadListener thread: http-nio-8080-exec-4 Read: 16384 bytes ReadListener thread: http-nio-8080-exec-5 Read: 16384 bytes ReadListener thread: http-nio-8080-exec-7 Read: 16384 bytes ReadListener thread: http-nio-8080-exec-6 Read: 16384 bytes ReadListener thread: http-nio-8080-exec-8 Read: 16384 bytes ReadListener thread: http-nio-8080-exec-9 Read: 16384 bytes ReadListener thread: http-nio-8080-exec-10 Read: 2312 bytes ReadListener thread: http-nio-8080-exec-1 Read: 48 bytes Total Read: 117202 bytes
可以從輸出看到除了doGet和第一次進(jìn)入onDataAvailable是同一個Http thread之外,后面的read動作都發(fā)生在另外的Http thread里。
這是因為客戶端的數(shù)據(jù)推送速度太慢了,容器先將Http thread收回,當(dāng)容器發(fā)現(xiàn)可以讀取到新數(shù)據(jù)的時候,再分配一個Http thread去讀InputStream,如此循環(huán)直到全部讀完為止。
注意:HttpServletRequest.getInputStream()和getParameter*()不能同時使用。
Async Write再來一段客戶端下載慢的例子,AsyncWriteServlet.java:
@WebServlet(value = "/async-write", asyncSupported = true) public class AsyncWriteServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("Servlet thread: " + Thread.currentThread().getName()); AsyncContext asyncCtx = req.startAsync(); ServletOutputStream os = resp.getOutputStream(); InputStream bigfileInputStream = ClassLoader.getSystemClassLoader().getResourceAsStream("bigfile"); os.setWriteListener(new WriteListener() { @Override public void onWritePossible() throws IOException { int loopCount = 0; System.out.println("WriteListener thread: " + Thread.currentThread().getName()); while (os.isReady()) { loopCount++; System.out.println("Loop Count: " + loopCount); byte[] bytes = readContent(); if (bytes != null) { os.write(bytes); } else { closeInputStream(); asyncCtx.complete(); break; } } } @Override public void onError(Throwable t) { try { os.print("Error happened"); os.print(ExceptionUtils.getStackTrace(t)); } catch (IOException e) { e.printStackTrace(); } finally { closeInputStream(); asyncCtx.complete(); } } private byte[] readContent() throws IOException { byte[] bytes = new byte[1024]; int readLength = IOUtils.read(bigfileInputStream, bytes); if (readLength <= 0) { return null; } return bytes; } private void closeInputStream() { IOUtils.closeQuietly(bigfileInputStream); } }); } }
同樣利用curl做慢速下載,curl --limit-rate 5k http://localhost:8080/async-write
接下來看以下服務(wù)端打印輸出:
Servlet thread: http-nio-8080-exec-1 WriteListener thread: http-nio-8080-exec-1 Write bytes: 8192 WriteListener thread: http-nio-8080-exec-2 Write bytes: 8192 WriteListener thread: http-nio-8080-exec-3 Write bytes: 8192 WriteListener thread: http-nio-8080-exec-4 Write bytes: 8192 WriteListener thread: http-nio-8080-exec-5 Write bytes: 8192 WriteListener thread: http-nio-8080-exec-6 Write bytes: 8192 WriteListener thread: http-nio-8080-exec-7 Write bytes: 8192 WriteListener thread: http-nio-8080-exec-8 Write bytes: 8192 WriteListener thread: http-nio-8080-exec-9 Write bytes: 8192 WriteListener thread: http-nio-8080-exec-10 Write bytes: 8192 WriteListener thread: http-nio-8080-exec-1 Write bytes: 8192 WriteListener thread: http-nio-8080-exec-2 Write bytes: 8192 WriteListener thread: http-nio-8080-exec-3 Write bytes: 8192 WriteListener thread: http-nio-8080-exec-4 Write bytes: 8192 WriteListener thread: http-nio-8080-exec-5 Write bytes: 2312
PS. 后發(fā)現(xiàn)即使沒有添加--limit-rate參數(shù),也會出現(xiàn)類似于上面的結(jié)果。
Jmeter上面兩個例子使用的是curl來模擬,我們也提供了Jmeter的benchmark。
需要注意的是,必須在user.properties文件所在目錄啟動Jmeter,因為這個文件里提供了模擬慢速連接的參數(shù)httpclient.socket.http.cps=5120。然后利用Jmeter打開benchmark.xml。
相關(guān)資料Java EE 7 Tutorial: Java Servlet Technology - Nonblocking I/O
Slides - Servlet 3.1 Async IO
Non-blocking I/O using Servlet 3.1: Scalable applications using Java EE 7
How to simulate network bandwidth in JMeter?
Configuring JMeter
Servlet 3.1 Asynchronous IO and Jetty-9.1
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/70853.html
摘要:異步處理簡介地址相關(guān)系列文章異步處理詳解分析本文講到的所有特性皆是基于的,不是基于的。用于異步返回結(jié)果,使用自己的,使用負(fù)責(zé)處理它。配置執(zhí)行異步操作需要用到,這個可以在用方法來提供相關(guān)文檔。 Spring MVC異步處理簡介 Github地址 相關(guān)系列文章: Servlet 3.0 異步處理詳解 Servlet 3.1 Async IO分析 本文講到的所有特性皆是基于Servlet...
摘要:概念響應(yīng)式編程,異步非阻塞就是響應(yīng)式編程,與之相對應(yīng)的是命令式編程。的另外一種實現(xiàn)方式就是消息隊列。非阻塞設(shè)計利用規(guī)范中的實現(xiàn)實現(xiàn)代碼鏈接 注: 本文是由讀者觀看小馬哥公開課視頻過程中的筆記整理而成。更多Spring Framework文章可參看筆者個人github: spring-framework-lesson 。 0. 編程模型與并發(fā)模型 Spring 5實現(xiàn)了一部分Reacti...
摘要:但是這樣依然有一個問題,考慮以下場景有一個容器,線程池大小。這個時候工程師發(fā)現(xiàn)了問題,擴(kuò)展了線程池大小到,但是負(fù)載依然持續(xù)走高,現(xiàn)在有個到,依然無法響應(yīng)。你可以修改的線程池大小,把它和比較結(jié)果來驗證這一結(jié)論。 Github地址 相關(guān)系列文章: Servlet 3.1 Async IO分析 Spring MVC異步處理的幾種方式 Servlet 3.0 開始提供了AsyncConte...
摘要:性能會有所降低一點內(nèi)容,刷新整個頁面用戶的操作頁面會中斷整個頁面被刷新了就是能夠做到局部刷新三對象是中最重要的一個對象。頭信息已經(jīng)接收,響應(yīng)數(shù)據(jù)尚未接收。 一、什么是Ajax Ajax(Asynchronous JavaScript and XML) 異步JavaScript和XML Ajax實際上是下面這幾種技術(shù)的融合: (1)XHTML和CSS的基于標(biāo)準(zhǔn)的表示技術(shù) (2)DOM進(jìn)...
摘要:攔截所有的請求,放行登錄頁面登錄操作請求,其余請求需要在登錄后才可訪問。同時配置參數(shù),指定要放行的路徑和請求的字符集。 Serlvet中WebServlet注解 作用: 用于將一個類聲明為 Servlet 描述: 該注解將會在部署時被容器處理, 容器將根據(jù)具體的屬性配置將相應(yīng)的類部署為 Servlet. 屬性詳解: 該注解具有下表給出的一些常用屬性(以下所有屬性均為可選屬性, 但是 v...
閱讀 3319·2021-11-23 09:51
閱讀 2436·2021-11-09 09:46
閱讀 1476·2019-08-30 15:54
閱讀 3121·2019-08-30 14:22
閱讀 2909·2019-08-29 12:40
閱讀 1629·2019-08-26 10:33
閱讀 1774·2019-08-23 17:09
閱讀 1553·2019-08-23 16:11