亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

本人最近研究Spring,得到以下結論,不知對不對,想請大家幫忙看看

本人最近研究Spring,得到以下結論,不知對不對,想請大家幫忙看看

元芳怎么了 2023-03-11 18:14:41
1、在多線程環境中,線程安全不安全都在于類里面有沒有成員變量,這些成員變量都是不安全的。2、pojo應該都設成prototype3、bean里面如果有成員變量,如String,int類型的成員變量,那這些成員變量肯定是不安全的,如果是引用其他bean,則要看引用的bean里面有沒有成員變量,如果有,則通常也應該是不安全的(除非這個引用的bean內容做了安全處理)。 4、一個單例bean A引用了一個多例的bean B為自己的成員變量,由于 beean A是單例,容器只加載一次,所以他所引用的beanB就不安全了。目前測試出來的唯一辦法是使用ThreadLocal<>來封裝beanB里面的成員變量,如下:@Service("serviceTest2")public class ServiceTest2Impl implements ServiceTest2{private ThreadLocal<GjjInfo> threadLocal=new ThreadLocal<GjjInfo>(); private GjjInfo getGjjInfo(){if(threadLocal.get()==null){System.out.println("gjjInfo為空,取一下");threadLocal.set(SpringContextHolder.getBean(GjjInfo.class));}return threadLocal.get();}public void start(Socket socket){GjjInfo gjjInfo=getGjjInfo(); System.out.println(Thread.currentThread().getName()+"|gjjInfo:"+gjjInfo.getAreaCode());gjjInfo.setAreaCode("bbbbbbbbb");}}這樣設計可以保證多線程環境中調用serviceTest2是線程安全的,但是在自己的當前線程中也不一定安全,例如,有一個serviceTest1一下子@Autowired了兩個serviceTest2(oneServiceTest2,twoServiceTest2),那么這兩個serviceTest2一模一樣(即便是用ThreadLocal<>封裝了),假如:情況1: oneServiceTest2處理業務邏輯到一半,轉頭又處理twoServiceTest2,肯定就有了臟讀的可能。情況2: oneServiceTest2處理結束,但是成員變量有變化,這時候再處理twoServiceTest2,則twoServiceTest2必然臟讀。所以我得到的結論是:在一次請求的整個生命周期,當前線程中某個帶有成員變量的bean,如果只被調用一次,那么用ThreadLocal<>來封裝成員變量,是沒有問題的,但是如果他被多次調用,那還是設成prototype比較好
查看完整描述

2 回答

?
慕雪6442864

TA貢獻1812條經驗 獲得超5個贊

你的問題都看了,其實就是線程安全問題,跟spring并沒有什么關系。需要清楚兩點

  1. 線程安全問題是多線程訪問共享數據才會存在的,這包括兩種情況,一是多線程訪問單例的成員變量,二是多線程訪問靜態變量(數據庫這里這就不算了)

  2. 線程內部不會產生安全問題,從java內存模型來看,一個線程對于對象的操作流程應該是,訪問主存中的對象并復制到工作內存當中,在工作內存中對副本做相應操作,操作完成后再寫入主存,線程見會產生線程安全問題,正是因為一個線程在操作工作內存中的副本時,在寫入主存之前,其他線程是不可見的,所以會產生問題,而線程內部,無論哪個方法怎么執行,對副本都是可見的,你說的兩種情況其實也是不存在的,情況1,如果你在一個線程中,一個方法執行到一半,去執行另一個方法,代碼怎么寫?肯定是在第一個方法中調用第二個方法,那么第二個方法執行完,第一個方法的后半部分肯定要接著第二個的邏輯寫,還接著第一個方法的前一半寫,那就是代碼寫錯了,情況2相同

這兩點應該可以解答你所有的問題


查看完整回答
反對 回復 2023-03-15
?
嚕嚕噠

TA貢獻1784條經驗 獲得超7個贊

Spring作為一個IOC/DI容器,幫助我們管理了許許多多的“bean”。但其實,Spring并沒有確保這些對象的線程安全,需要由開發者自己編寫解決線程安全問題的代碼。
Spring對每個bean提供了一個scope屬性來表示該bean的作用域。它是bean的生命周期。

我們知道在一般情況下,只有無狀態的Bean才可以在多線程環境下共享,在Spring中,絕大部分Bean都可以聲明為singleton作用域。就是因為Spring對一些Bean(如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等)中非線程安全狀態采用ThreadLocal進行處理,讓它們也成為線程安全的狀態,因為有狀態的Bean就可以在多線程中共享了。
一般的Web應用劃分為展現層、服務層和持久層三個層次,在不同的層中編寫對應的邏輯,下層通過接口向上層開放功能調用。在一般情況下,從接收請求到返回響應所經過的所有程序調用都同屬于一個線程。
ThreadLocal是解決線程安全問題一個很好的思路,ThreadLocal是一個為線程提供線程局部變量的工具類。它的思想也十分簡單,就是為線程提供一個線程私有的變量副本,這樣多個線程都可以隨意更改自己線程局部的變量,不會影響到其他線程。不過需要注意的是,ThreadLocal提供的只是一個淺拷貝,如果變量是一個引用類型,那么就要考慮它內部的狀態是否會被改變,想要解決這個問題可以通過重寫ThreadLocal的initialValue()函數來自己實現深拷貝,建議在使用ThreadLocal時一開始就重寫該函數。
ThreadLocal通過為每個線程提供一個獨立的變量副本解決了變量并發訪問的沖突問題。在很多情況下,ThreadLocal比直接使用synchronized同步機制解決線程安全問題更簡單,更方便,且結果程序擁有更高的并發性。
如果你的代碼所在的進程中有多個線程在同時運行,而這些線程可能會同時運行這段代碼。如果每次運行結果和單線程運行的結果是一樣的,而且其他的變量的值也和預期的是一樣的,就是線程安全的。
或者說:一個類或者程序所提供的接口對于線程來說是原子操作或者多個線程之間的切換不會導致該接口的執行結果存在二義性,也就是說我們不用考慮同步的問題。

 


查看完整回答
反對 回復 2023-03-15
  • 2 回答
  • 0 關注
  • 114 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號