<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    吳密的博客

    每天進步一點點
    posts - 12, comments - 1, trackbacks - 0, articles - 1

    threadLocal--簡單本地緩存

    Posted on 2010-09-10 13:44 xiaolang 閱讀(5651) 評論(0)  編輯  收藏

     

    首先,ThreadLocal 不是用來解決共享對象的多線程訪問問題的,一般情況下,通過ThreadLocal.set() 到線程中的對象是該線程自己使用的對象,其他線程是不需要訪問的,也訪問不到的。各個線程中訪問的是不同的對象。

    另外,說ThreadLocal使得各線程能夠保持各自獨立的一個對象,并不是通過ThreadLocal.set()來實現的,而是通過每個線程中的new 對象 的操作來創建的對象,每個線程創建一個,不是什么對象的拷貝或副本。

    個人版中有一個比較好的應用場景,就是為會員查詢服務做的catche

    在用戶的一次請求中需要多次查詢用戶的卡信息,會多次去調用遠程服務,造成性能上的浪費。如果能在本地做一個簡單的cache,就可以省去遠程調用的開銷,就可以如下圖所示

                                                                     
                           

    從圖中可以看出,優化后的將一部分cache存在本地,就省去了遠程調用的開銷,從一定程度上減輕了會員核心的壓力。

    Cache
    一般都有一個刷新時間的問題,時間長了,信息可能不準確,時間短了,比較耗費性能。最好的情況是這個cache過期了,不需要使用了,立即把清除,廢棄,這個最理想的情況。

    大家應該知道,用戶從發起請求,到服務器響應的這個過程中,在服務器中是在一個線程中的。如果我們吧查詢出來的東西放到這個線程中,到用戶請求結束時,把這些東西清理掉,應該是一個不錯的cache方案。

    接下來的問題就簡單了,我們只需要把查詢的東西放到threadLocal就可以了。

    看大牛李磊如何實現這一點

    1.   
    首先需要初始化一個threadLocal

        /** 用于將會員信息保存在本地的線程變量*/

        private static ThreadLocal<List<UserInfo>>            localUserInfo      = new ThreadLocal<List<UserInfo>>() {
                                                                                     protected synchronized List<UserInfo> initialValue() {
                                                                                         return new ArrayList<UserInfo>();
                                                                                     } };

     
    2.   
    將查詢出來的東西放到threadLocal,下次查詢的時候,就可以先到threadLocal中取,如果沒有,再調用遠程服務

            UserInfo userInfo = getFromLocalByCardNo(cardNo);
            if (userInfo == null) {
                userInfo = userInfoQueryService.findUserInfo(cardNo);
                putToLocal(userInfo);
            }
     
    3
    .用戶的請求結束,把這些內容清理掉。
    為什么要把內容清理掉
    如果一直存放在threadLocal

    1是比較耗費內存;

    2是里面的內容可能是過期的(用戶修改了信息,threadLocal里面沒有更新)

    3請求結束后需要清除ThreadLocal的一個很重要的原因就是,如果使用了線程池,在請求結束后,線程的生命周期還沒有結束,而是放回到池中,這樣下次再使用此線程的時候就會獲得上次的上下文了。

    我們如何做到這一點呢?
    開始之前先給大家介紹一個接口,spring mvc中的。HandlerInterceptor

    這個接口中有三個方法
    preHandle
    在一個該方法會在Controller的方法執行前會被調用,可以使用這個方法來中斷或者繼續執行鏈的處理,當返回true時,處理執行鏈會繼續,當返回false時,則不會去執行Controller的方法
    postHandle
    3個方法會在在controller的方法執行之后,在DispatcherServlet類導向到view進行render之前依次執行。最有用的是使 用postHandleRender方法,因為它有ModelAndView 傳進來,那么我們就可以在render view之前往view中添加額外的model對象,或者對view的去處進行修改(例如下面的HTML還是用Excel來作為View ”例子就是對view進行了更改)

    afterCompletion
    該方法會在render view完成后執行,也可以說在請求過程(request processing)完成之后執行。該方法可以用來清理資源(例如象blackboard building block release context)

    我們只需要在afterCompletion中把本次線程中的存放的信息清理掉,就可以了。
    大家應該記得這一段代碼,初始化threadLocal并不需要這一點,

         static {
            ThreadLocalCleaner.register(localUserInfo);
            ThreadLocalCleaner.register(localCertifyStatus);
        }

    讓我們先看下ThreadLocalCleaner的代碼

        /**
         *
    清理所有的線程變量。
         */
        public static void clear() {
            for (ThreadLocal<?> tl : tls) {
                tl.remove();
            }
        }

        /**
         * @param tl
         */
        public static void register(ThreadLocal<?> tl) {
            tls.add(tl);
        }
     
    方 法register將初始化的ThreadLocal放到一個總的ThreadLocal里,方法clear將總的ThreadLocal里面的內容清 空。我們只需要在HandlerInterceptor實現類中的afterCompletion方法中把clear調用一下就可以了。

     


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 亚洲欧洲av综合色无码 | 成人免费一区二区三区| 日本高清色本免费现在观看| 亚洲国产品综合人成综合网站| 永久在线免费观看| 亚洲精品欧洲精品| 日韩亚洲国产高清免费视频| 亚洲人成在线播放| 久久久www成人免费毛片| 欧洲 亚洲 国产图片综合| 成人免费视频88| 久久精品国产亚洲AV天海翼| 高清在线亚洲精品国产二区| 一级毛片正片免费视频手机看| 中文字幕日韩亚洲| 成人爽a毛片免费| 亚洲精品在线免费观看| 丁香花免费高清视频完整版| 亚洲成AV人影片在线观看| 亚洲第一成人影院| 两个人看的www视频免费完整版| 久热综合在线亚洲精品| 免费在线观看视频网站| 亚洲AV无码一区二区三区久久精品| 国产免费无遮挡精品视频| 免费一级毛suv好看的国产网站| 亚洲精品成人片在线播放| 中文字幕亚洲免费无线观看日本| 亚洲乱码一二三四区乱码| 亚洲 无码 在线 专区| a级毛片无码免费真人久久| 亚洲成人免费网站| 亚洲国产婷婷香蕉久久久久久| 久草视频在线免费看| 日韩亚洲产在线观看| 亚洲综合色成在线播放| 欧洲一级毛片免费| jzzjzz免费观看大片免费| 亚洲第一二三四区| 亚洲国产av无码精品| 成人免费福利视频|