真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

tomcat下使用Servlet異步模式的方法

這篇文章主要介紹“tomcat下使用Servlet異步模式的方法”,在日常操作中,相信很多人在tomcat下使用Servlet異步模式的方法問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”tomcat下使用Servlet異步模式的方法”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

成都網(wǎng)站設(shè)計(jì)、做網(wǎng)站中從網(wǎng)站色彩、結(jié)構(gòu)布局、欄目設(shè)置、關(guān)鍵詞群組等細(xì)微處著手,突出企業(yè)的產(chǎn)品/服務(wù)/品牌,幫助企業(yè)鎖定精準(zhǔn)用戶,提高在線咨詢和轉(zhuǎn)化,使成都網(wǎng)站營銷成為有效果、有回報(bào)的無錫營銷推廣。創(chuàng)新互聯(lián)專業(yè)成都網(wǎng)站建設(shè)十載了,客戶滿意度97.8%,歡迎成都創(chuàng)新互聯(lián)客戶聯(lián)系。

servlet3.0版本以后,增加了對異步模式的支持。

    以往在servlet里面,每一個新的請求到來都會由一個線程來接收處理,在處理過程中如果需要等待其他操作的結(jié)果,則線程就會處于阻塞狀態(tài)不能執(zhí)行其他任務(wù),待任務(wù)結(jié)束后該線程將結(jié)果輸出給客戶端,這時該線程才能繼續(xù)處理其他的請求。為了提高線程利用效率,servlet3.0版本以后增加了異步處理請求的模式,允許當(dāng)前線程將任務(wù)提交到給其他后臺線程處理(一般是后臺線程池,這樣只需要較少的線程就可以處理大量的任務(wù)),自身轉(zhuǎn)而去接收新的請求。

  protected void service(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException {
        response.getWriter().println("hello");
    }

    要使用異步模式,只需要調(diào)用request對象的startAsync方法即可,該方法返回一個AsyncContext對象供后續(xù)使用,可以通過該對象設(shè)置異步處理的超時間,添加異步處理的監(jiān)聽器等。然后將要處理的任務(wù)提交到某個線程池,當(dāng)前線程執(zhí)行完后續(xù)的代碼后就能去處理其他新的請求,不用等待當(dāng)前任務(wù)執(zhí)行完。當(dāng)前任務(wù)交由后臺線程池執(zhí)行完后,可以調(diào)用asyncContext.complete方法表示任務(wù)處理完成,觸發(fā)之前添加的監(jiān)聽器對事件進(jìn)行響應(yīng)。

protected void service(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException {
        //啟用異步模式
        final AsyncContext ac = request.startAsync();
        //超時設(shè)置
        ac.setTimeout(1000L);
        //添加監(jiān)聽器便于觀察發(fā)生的事件
        ac.addListener(new AsyncListener() {
            @Override
            public void onComplete(AsyncEvent asyncEvent) throws IOException {
                System.out.println("onComplete");
            }
            @Override
            public void onTimeout(AsyncEvent asyncEvent) throws IOException {
                System.out.println("onTimeout");
            }
            @Override
            public void onError(AsyncEvent asyncEvent) throws IOException {
                System.out.println("onError");
            }
            @Override
            public void onStartAsync(AsyncEvent asyncEvent) throws IOException {
                System.out.println("onStartAsync");
            }
        });

        executor.submit(new Runnable() {
            @Override
            public void run() {
                //這里可以使用request, response,ac等對象
                try {
                    String user = request.getParameter("user");
                    response.getWriter().println("hello from async " + user);
                    ac.complete();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
        //方法結(jié)束當(dāng)前線程可以去處理其他請求了
    }

    由于asyncContext對象中持有請求中的request和response對象,所以在任務(wù)異步執(zhí)行完后仍然可以通過response將結(jié)果輸出給客戶端。但是,tomcat在經(jīng)過超時間之后還未收到complete消息,會認(rèn)為異步任務(wù)已經(jīng)超時,需要結(jié)束當(dāng)前的請求,從而將response對象放回對象池供其他請求繼續(xù)使用。這時response對象會分配給新的請求使用,按理就不應(yīng)該再被之前的異步任務(wù)共用!但是異步任務(wù)本身并不知道任務(wù)已經(jīng)超時了,還在繼續(xù)運(yùn)行,因此還會使用response對象進(jìn)行輸出,這時就會發(fā)生新的請求與后臺異步任務(wù)共同一個resonse對象的現(xiàn)象!這會造成多個線程向同一個客戶端輸出結(jié)果,將本不是該客戶端需要的結(jié)果輸出。試想一下:本來請求是的查詢我的訂單列表,結(jié)果收到了別人的訂單列表,這個后果是不是很嚴(yán)重呢?

為驗(yàn)證這個問題,可以使用以下代碼進(jìn)行測試:

package async;

import javax.servlet.AsyncContext;
import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class AsyncTimeoutServlet extends HttpServlet {

    boolean running = false;
    boolean stop = false;
    ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 50000L,
            TimeUnit.MILLISECONDS, new ArrayBlockingQueue(100));

    @Override
    public void init() throws ServletException {
        System.out.println("init AsyncTimeoutServlet");
    }

    @Override
    public void destroy() {
        executor.shutdownNow();
    }

    protected void service(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException {
        stop = "true".equals(request.getParameter("stop"));
        //這里只對第一次請求使用異步模式,后續(xù)請求均使用同步模式
        if (running) {
            System.out.println("running");
            try {
                //在同步模式下輸出response對象的hashcode
                response.getWriter().println("this response belong's to you:" + response.toString());
            } catch (IOException e) {
                System.out.println("response error");
            }
            return;
        }
        running = true;

        //啟用異步模式
        final AsyncContext ac = request.startAsync();
        System.out.println("startAsync");
        //超時設(shè)置為1s便于快速超時
        ac.setTimeout(1000L);
        //添加監(jiān)聽器便于觀察發(fā)生的事件
        ac.addListener(new AsyncListener() {
            @Override
            public void onComplete(AsyncEvent asyncEvent) throws IOException {
                System.out.println("onComplete");
            }

            @Override
            public void onTimeout(AsyncEvent asyncEvent) throws IOException {
                System.out.println("onTimeout");
            }

            @Override
            public void onError(AsyncEvent asyncEvent) throws IOException {
                System.out.println("onError");
            }

            @Override
            public void onStartAsync(AsyncEvent asyncEvent) throws IOException {
                System.out.println("onStartAsync");
            }
        });

        executor.submit(new Runnable() {
            @Override
            public void run() {
                while (!stop) {
                    try {
                        //每隔3s向原始的response對象中輸出結(jié)果,便于客戶端觀察是否有收到該結(jié)果
                        Thread.sleep(3000L);
                        System.out.println("async run");
                        try {

                            response.getWriter().println("if you see this message, something must be wrong. I'm " + response.toString());
                        } catch (IOException e) {
                            System.out.println("async response error");
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        return;
                    }
                }
                System.out.println("stop");
            }
        });
        System.out.println("ok, async mode started.");
    }
}

在上面的測試示例中,我們對第一次請求開啟了異步模式,后續(xù)的請求仍然采用同步模式,并只是簡單地輸出response對象的hashcode,將一個任務(wù)提交到了線程池中運(yùn)行。在異步任務(wù)里每隔3s向客戶端輸出一次response對象的hashcode,而這個response對象是第一個請求的response對象,也就是說,它應(yīng)該與后續(xù)的請求使用了不同的response對象才對。但是在多次調(diào)用該servlet后,有些請求得到的結(jié)果中包含了第一次請求時產(chǎn)生的異步任務(wù)中輸出的內(nèi)容,也就是后續(xù)的有些請求與第一次請求共用了同一個response對象,tomcat對response對象進(jìn)行了重用!

測試結(jié)果如下:

curl -i "http://127.0.0.1:8080/servlet_async/async"
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Length: 192
Date: Wed, 21 Aug 2019 07:55:26 GMT

if you see this message, something must be wrong. I'm org.apache.catalina.connector.ResponseFacade@51582d92
this response belong's to you:org.apache.catalina.connector.ResponseFacade@51582d92

并不是每一次請求都能成功重用到同一個response,所以上述請求有可能需要運(yùn)行多次才能出現(xiàn)預(yù)期的結(jié)果。

避坑方法:

異步任務(wù)如果需要使用response對象,先判斷當(dāng)前異步模式是否已經(jīng)超時和結(jié)束了,如果結(jié)束了則不要再使用該對象,使用request對象也是同理。不過,有時候我們會把request對象傳入異步任務(wù),在任務(wù)執(zhí)行的時候會從中取出一些數(shù)據(jù)使用,比如getParameter獲取參數(shù),這種情況下可以事先從request對象中獲取到異步任務(wù)需要的所有數(shù)據(jù),封裝成新的對象供異步任務(wù)使用,避免使用tomcat提供的request對象。

到此,關(guān)于“tomcat下使用Servlet異步模式的方法”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!


分享文章:tomcat下使用Servlet異步模式的方法
文章分享:http://weahome.cn/article/iecpcs.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部