日韩性视频-久久久蜜桃-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 | 波多野结衣av一区二区全免费观看 | 日韩在线播放中文字幕 | 69视频一区二区 | 91九色国产 | 国语对白在线观看 | 色站综合 | 无码黑人精品一区二区 | 国产女人18毛片水真多18精品 | 精精国产 | 色女人网 | 免费男女乱淫真视频免费播放 | 国产伊人一区 | 亚洲综合在线中文字幕 | 亚洲天堂免费观看 | 初高中福利视频网站 | 国内精品久久久 | 国产精品黄色在线观看 | 男女男精品视频站 | ass日本寡妇pics | 欧美亚洲一 | 免费网站在线观看视频 | 日本免费小视频 | 亚洲一区二区中文字幕 | 久久亚洲a v| 日韩骚片 | 香蕉视频首页 | 日韩69 | 香蕉视频免费看 | 久久99精品国产.久久久久 | 精品国产av无码一区二区三区 | 最近中文字幕在线观看视频 | 男男gay做受xx | 亚洲三级理论 | 亚洲国产小视频 | 伊人久久一区二区三区 | 国产69精品久久久久久久 | 999综合网| 国产精品一页 | 亚洲精品电影在线观看 | 国产日韩在线一区 | 男女一区二区三区 | 男女男精品网站 | 日本大尺度吃奶做爰久久久绯色 | 国产精品中文在线 | 成人性视频免费网站 | 夫妻露脸自拍[30p] | 精品一卡二卡 | 精品少妇一区二区三区在线观看 | 日韩一区二区欧美 | 9久9久9久女女女九九九一九 | 亚洲福利视频导航 | 玩弄丰满少妇xxxxx性多毛 | 小泽玛利亚一区二区三区在线观看 | 国产精品国产成人国产三级 | av超碰在线观看 | 佐山爱av在线 | 蜜臀av性久久久久蜜臀av麻豆 | 色香蕉视频 | 偷偷草| 欧美性猛交性大交 | 四虎影视8848hh | 乱子伦一区二区 | 四虎黄网 | 久久久123| 宅男深夜视频 | 99久久久国产精品无码网爆 | av看片资源| 在线电影一区 | 丰满少妇被猛烈进入高清播放 | www.国产毛片 | 日韩在线观看视频一区 | 夜夜骑天天操 | 手机在线看片日韩 | 日韩美女黄色 | 国产一区在线免费观看 | 1024毛片| 国产成人中文字幕 | 国模无码视频一区二区三区 | 韩国精品一区二区 | 亚洲三级视频在线观看 | 直接看的av网站 | 精品人妻少妇AV无码专区 | 精品亚洲国产成人av制服丝袜 | 午夜电影天堂 | av在线影音 | 日本特黄特黄刺激大片 | 99热只有这里有精品 | 欧美中出 | 96精品视频| 色中文字幕在线观看 | 欧美大肚乱孕交hd孕妇 | 国产黄a | 貂蝉被到爽流白浆在线观看 | 国产成人在线观看网站 | www一起操| 午夜私人福利 | 欧美激情在线观看视频 |