中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

java高并發中如何進行線程封閉

發布時間:2021-10-19 16:17:48 來源:億速云 閱讀:126 作者:柒染 欄目:大數據

這篇文章給大家介紹java高并發中如何進行線程封閉,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

很多時候都想躲避并發,避免并發除了設計成不可變對象其實還有一個簡單的方法就是線程封閉。

什么是線程封閉?

其實就是把對象封裝到一個線程里,只有這一個線程能看到這個對象。那么這個對象就算不是線程安全的,也不會出現線程安全方面的問題了,因為他只能在一個線程里面進行訪問。那么如何實現線程封閉呢?

如何實現線程封閉?

  • Ad-hoc 線程封閉:程序控制實現,最糟糕,忽略

  • 堆棧封閉:局部變量,無并發問題。是我們現實中使用最多的封閉了,簡單說就是局部變量。多個線程訪問一個方法的時候,方法中的局部變量都會被拷貝一份到線程棧中,所以局部變量是不會被線程共享的,因此不會出現并發問題。所以全局變量容易引起并發問題。

  • ThreadLocal線程封閉:特別好的封閉方法。ThreadLocal內部維護了一個map,key是線程的名稱,value就是封閉的對象。

 ThreadLocal

正常來講我們每一個請求對服務器來講都是一個線程在運行,我們希望線程間隔離,一個線程在被后端服務器實際處理的時候,可以通過Filter過濾器取出當前的用戶,然后將數據存放在ThreadLocal中,當線程被接口的service以及其他相關類進行處理的時候很可能需要在取出當前用戶,這時就可以隨時隨地從ThreadLocal中直接拿到之前存儲的值這樣用起來就很方便了。如果我們不這樣做,會有什么麻煩呢?因為我們的登錄用戶通常是從request中取出來的,因此需要帶上request或者從request中取出來的用戶信息,從controller層開始不停的往下傳,甚至會傳到一些util類中,這樣會使得代碼看起來很臃腫。當使用ThreadLocal和Filter,就可以很方便的在接口處理之前,前取出相關的信息,在接口實際處理的時候,什么時候需要什么時候再把信息取出來,這樣代碼在設計的時候就容易多了,不至于把request從controller一直傳遞下去。

具體使用實例如下:

新建一個類:

public class RequestHolder {
    //因為當前沒有登錄用戶,我們用線程id來充當
    private final static ThreadLocal<Long> requestHolder = new ThreadLocal<>();

    /**
     * 請求進入到后端服務器,但是還沒有實際處理的時候調用add,可以使用Filter
     * @param id
     */
    public static void add(Long id) {
        //雖然只傳入id,但是threadLocal會取出當前線程id放到map中的key,value是傳入的值
        requestHolder.set(id);
    }

    public static Long getId() {
        return requestHolder.get();
    }

    /**
     * 如果不做remove的話,會造成內存泄漏,數據永遠不會釋放掉
     * 需要在接口真正處理完成之后進行調用,可以使用interceptor
     */
    public static void remove() {
        requestHolder.remove();
    }
}

這個類就用來存放ThreadLocal。

新建一個Filter:

@Slf4j
public class HttpFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
//        httpServletRequest.getSession().getAttribute("user");
        log.info("do filter , {}, {}", Thread.currentThread().getId(), ((HttpServletRequest) request).getServletPath());
        RequestHolder.add(Thread.currentThread().getId());
        // 如果這個Filter不想攔截住這個請求,只想做單獨的數據處理時,要調用chain.doFilter,使得攔截器處理完
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {

    }
}

新建一個Interceptor:

@Slf4j
public class HttpInterceptor extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("preHandle");
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        RequestHolder.remove();
        log.info("afterCompletion");
        return ;
    }
}

配置filter和interceptor:

@Configuration
public class Config implements WebMvcConfigurer {

    @Bean
    public FilterRegistrationBean<HttpFilter> httpFilter(){
        FilterRegistrationBean<HttpFilter> filterRegistrationBean = new FilterRegistrationBean<>();
        // 設置filter
        filterRegistrationBean.setFilter(new HttpFilter());
        // 攔截規則
        filterRegistrationBean.addUrlPatterns("/threadLocal/*");
        return filterRegistrationBean;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new HttpInterceptor()).addPathPatterns("/**");
    }
}

新建一個controller進行測試:

@RestController
@RequestMapping("threadLocal")
public class ThreadLocalController {

    @GetMapping("/test")
    public Long test() {
        return RequestHolder.getId();
    }

}

在瀏覽器中輸入localhost:8080/threadLocal/test可以輸出線程的id,與后臺的輸出id一致。

關于java高并發中如何進行線程封閉就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

永和县| 东兴市| 木里| 龙口市| 东源县| 临澧县| 察隅县| 荣昌县| 衡水市| 嘉义县| 合山市| 元氏县| 文昌市| 拜城县| 胶南市| 新龙县| 德惠市| 富阳市| 万宁市| 惠水县| 新营市| 博湖县| 察哈| 克拉玛依市| 蒙城县| 衡南县| 漯河市| 马鞍山市| 塔城市| 民乐县| 青神县| 嘉鱼县| 威海市| 黄骅市| 蓝田县| 平阴县| 墨竹工卡县| 武威市| 阜宁县| 剑阁县| 霍林郭勒市|