日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

并发编程-11线程安全策略之线程封闭

發布時間:2025/3/21 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 并发编程-11线程安全策略之线程封闭 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 腦圖
  • 概述
  • 線程封閉的三種方式
  • 示例
    • 堆棧封閉
    • ThreadLocal
    • Step1. ThreadLocal操作類
    • Step2. 自定義過濾器
    • Step3. 注冊攔截器,配置攔截規則
    • Step4. Controller層調用
    • Step5. 測試
  • 代碼

腦圖


概述

在上篇博文并發編程-10線程安全策略之不可變對象 ,我們通過介紹使用線程安全的不可變對象可以保證線程安全。

除了上述方法,還有一種辦法就是:線程封閉。


線程封閉的三種方式

  • Ad-hoc 線程封閉 ,完全由程序控制實現,不可控,不要使用

  • 堆棧封閉 方法中定義局部變量。不存在并發問題

堆棧封閉其實就是方法中定義局部變量。不存在并發問題。

多個線程訪問一個方法的時候,方法中的局部變量都會被拷貝一份到線程的棧中(Java內存模型),所以局部變量是不會被多個線程所共享的。

局部變量的固有屬性之一就是封閉在線程中。它們位于執行線程的棧中,其他線程無法訪問這個棧。

Java虛擬機棧 請參考以前的博文 地址如下: https://blog.csdn.net/yangshangwei/article/details/52833342#java%E8%99%9A%E6%8B%9F%E6%9C%BA%E6%A0%88-java-virtual-machine-stacks


  • ThreadLocal 線程封閉 將可變數據通過每個線程有自己的獨立副本從而實現線程封閉的機制

ThreadLocal類:線程本地變量。如果將變量使用ThreadLocal來包裝,那么每個線程往這個ThreadLocal中讀寫都是線程隔離的,互相之間不會影響。

它提供了一種將可變數據通過每個線程有自己的獨立副本從而實現線程封閉的機制。

Thread類有一個類型為ThreadLocal.ThreadLocalMap的實例變量threadLocals,也就是說每個線程有一個自己的ThreadLocalMap。

ThreadLocalMap有自己的獨立實現,可以簡單地將它的key視作ThreadLocal,value為代碼中放入的值(實際上key并不是ThreadLocal本身,而是它的一個弱引用)。

每個線程在往某個ThreadLocal里set值的時候,都會往自己的ThreadLocalMap里存,get也是以某個ThreadLocal作為引用,在自己的map里找對應的key,從而實現了線程隔離。


示例

堆棧封閉

多個線程訪問一個方法,該方法中的局部變量都會被拷貝一份兒到線程棧中。所以局部變量是不被多個線程所共享的,也就不會出現并發問題。所以能用局部變量就別用全局的變量,全局變量容易引起并發問題。

局部變量,沒啥好說的 ,直接看ThreadLocal實現線程安全吧


ThreadLocal

假設我們將用戶信息放到ThreadLocal中,然后從ThreadLocal中獲取該用戶信息。 這個例子中的場景不是很嚴謹,僅僅僅是為了演示ThreadLocal的用法

這里我們通過攔截器(過濾器也行) ,【如果過濾器和攔截器不清楚的話,建議先看下我之前寫的博文: Spring Boot2.x-12 Spring Boot2.1.2中Filter和Interceptor 的使用 】在調用Controller之前 ,重寫攔截器的preHandle方法,通常情況下在該方法中從session中獲取user信息,將寫入到ThreadLocal, 重寫afterCompletion方法不管是方法執行正常還是異常都會執行該方法,在該方法中移除threadlocal中的值,否則累計太多容易造成內溢出。

Step1. ThreadLocal操作類

通常情況下都要具備三個方法 add get remove 。特別是remove,否則容易造成內存溢出

package com.artisan.example.threadLocal;import lombok.extern.slf4j.Slf4j;/*** 通常情況下都要具備三個方法 add get remove * 特別是remove,否則容易造成內存泄漏* @author yangshangwei**/ @Slf4j public class RequestHolder {private final static ThreadLocal<ArtisanUser> USER_HOLDER = new ThreadLocal<ArtisanUser>();public static void addCurrentUser(ArtisanUser artisanUser) {// 將當前線程作為key, artisanUser作為value 存入ThreadLocal類的ThreadLocalMap中USER_HOLDER.set(artisanUser);log.info("將artisanUser:{} 寫入到ThreadLocal",artisanUser.toString());}public static ArtisanUser getCurrentUser() {// 通過當前線程這個key ,獲取存放在當前線程的ThreadLocalMap變量中的valueArtisanUser artisanUser = USER_HOLDER.get();log.info("從ThreadLocal中獲取artisanUser:{}",artisanUser.toString());return artisanUser;}public static void removeCurrentUser() {log.info("從ThreadLocal中移除artisanUser:{}", getCurrentUser());// 通過當前線程這個key獲取當前線程的ThreadLocalMap,從中移除valueUSER_HOLDER.remove();}}

Step2. 自定義過濾器

在過濾器中 ,重寫對應的方法 添加 和 移除 threadLocal

package com.artisan.interceptors;import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;import org.checkerframework.checker.index.qual.LengthOf; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView;import com.artisan.example.threadLocal.ArtisanUser; import com.artisan.example.threadLocal.RequestHolder;import lombok.extern.slf4j.Slf4j;/*** 實現 Handlerlnterceptor接口,覆蓋其對應的方法即完成了攔截器的開發* * @author yangshangwei**/ @Slf4j public class MyInterceptor implements HandlerInterceptor {/*** preHandle在執行Controller之前執行 * 返回true:繼續執行處理器邏輯,包含Controller的功能 * 返回false:中斷請求* * 處理器執行前方法*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {log.info("MyInterceptor-處理器執行前方法preHandle,返回true則不攔截后續的處理");// 模擬user存在session中ArtisanUser user = new ArtisanUser();user.setName("artisan");user.setAge(20);request.getSession().setAttribute("user", user);// 將用戶信息添加到ThreadLocal中RequestHolder.addCurrentUser((ArtisanUser)request.getSession().getAttribute("user"));return true;}/*** postHandle在請求執行完之后渲染ModelAndView返回之前執行* * 處理器處理后方法*/@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception {}/*** afterCompletion在整個請求執行完畢后執行,無論是否發生異常都會執行* * 處理器完成后方法* * * 在這個方法中移除當前用戶*/@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {log.info("MyInterceptor-處理器完成后方法afterCompletion");RequestHolder.removeCurrentUser();}}

Step3. 注冊攔截器,配置攔截規則

注冊攔截器,配置攔截規則

package com.artisan.config;import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import com.artisan.interceptors.MyInterceptor;/*** 實現 WebMvcConfigurer 接 口, 最后覆蓋其addInterceptors方法進行注冊攔截器* @author yangshangwei**/// 標注為配置類 @Configuration public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 注冊攔截器到 Spring MVC 機制, 然后 它會返 回 一個攔截器注冊InterceptorRegistration regist = registry.addInterceptor(new MyInterceptor());// 指定攔截匹配模式,限制攔截器攔截請求regist.addPathPatterns("/artisan/threadLocal/*");}}

Step4. Controller層調用

通過RequestHolder.getCurrentUser() 獲取存到ThreadLocal中的user信息

package com.artisan.controller;import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;import com.artisan.example.threadLocal.ArtisanUser; import com.artisan.example.threadLocal.RequestHolder;@RestController @RequestMapping("/artisan/threadLocal") public class ThreadLocalTestController {@GetMapping("/getCurrentUser")public ArtisanUser getCurrentUser() {return RequestHolder.getCurrentUser();} }

Step5. 測試

啟動Spring Boot 工程,打開postman,請求

http://localhost:8080/artisan/threadLocal/getCurrentUser

postman 或者瀏覽器

控制層可以直接通過RequestHold這個threalocal封裝類直接獲取到存放在ThreadLocal中的變量信息,說明OK。

觀察后臺日志:


代碼

https://github.com/yangshangwei/ConcurrencyMaster

總結

以上是生活随笔為你收集整理的并发编程-11线程安全策略之线程封闭的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 最新av免费观看 | 青青在线 | 日韩黄片一区二区 | 1级性生活片 | 亚洲视频一区二区三区在线观看 | 久久精品午夜 | 中文字幕在线视频播放 | 欧美色图激情 | 久久国精品 | 东北少妇不戴套对白第一次 | 免费不卡的av | 欧美性大战久久久久久久 | 丝袜国产在线 | 久久综合亚洲色hezyo国产 | 97久久久| 亚洲欧美日韩中文在线 | 国产伦精品一区二区三区照片 | 亚洲一级片在线播放 | 春色激情站| 国产欧美日韩综合精品一区 | 黄视频网站在线 | 91尤物视频 | 亚洲一区第一页 | 一级一片免费播放 | 黄色一区二区三区 | 91精品在线一区 | 国产精品人八做人人女人a级刘 | 亚洲国产综合视频 | 国产视频成人 | 性——交——性——乱免费的 | 日本亚洲最大的色成网站www | 日本三级一区二区三区 | 黄色av毛片 | 国产av电影一区二区三区 | 天天舔天天射天天干 | 久久久成人精品 | 免费动漫av| 91大神在线免费观看 | 亚洲综合在线播放 | 日本在线播放一区 | 官场艳妇疯狂性关系 | 欧美精品一级在线观看 | 妺妺窝人体色www在线下载 | 超碰丝袜 | 日本少妇性高潮 | 一本高清dvd在线播放 | 久久av在线 | 亚洲欧美日韩综合一区二区 | 久久精品一日日躁夜夜躁 | 日本女人毛片 | 福利资源导航 | 精品久久久久久无码国产 | 午夜黄色在线 | 久久这里只有 | 中文字幕免费在线 | 亚洲色成人网站www永久四虎 | 自拍偷拍欧美视频 | 曰本无码人妻丰满熟妇啪啪 | 一区二区三区四区国产精品 | 亚洲国产成人在线 | 国产精品久久久久影院老司 | ass日本寡妇pics| 不卡av免费观看 | 一本色道久久综合亚洲精品图片 | 精品久久一区二区 | 亚洲二区中文字幕 | 成人精品视频一区二区三区尤物 | 精产国产伦理一二三区 | 中文字幕免费高清在线 | ass亚洲熟妇毛耸耸pics | 成人激情视频在线播放 | 中国一级特黄录像播放 | 久久久精品国产免费爽爽爽 | 成人精品视频在线观看 | 精品少妇3p| 天天上天天干 | av高清在线观看 | 欧美色图19p | 粉嫩av一区二区三区四区五区 | 乱色专区| 亚洲不卡影院 | 69精品在线观看 | a猛片| 国产麻豆成人精品av | 国产十八熟妇av成人一区 | 欧美大波大乳巨大乳 | 久久久久久久久免费视频 | 性生活视频网站 | 青青成人在线 | 久久亚洲无码视频 | 欧美日韩性生活 | 吃瓜网今日吃瓜 热门大瓜 色婷在线 | 又黄又色| 成年人视频在线免费看 | 91插插视频 | 日本一区免费 | 无码人妻熟妇av又粗又大 | 一区二区高清在线观看 | 午夜免费福利在线 |