spring創建的對象時當線程,當多線程時產生安全問題?


1.spring默認的作用域

單例 singleton 整個應用中只創建一個實例
原型 prototype 每次注入時都新建一個實例
會話 session 為每個會話創建一個實例
請求 request 為每個請求創建一個實例

 

 

 

 

 

2.解釋一波單例模式

   餓漢式,懶漢式(不安全,使用的時候再創建)

單例模式是一種對象創建型模式,使用單例模式,可以保證為一個類只生成唯一的實例對象。也就是說,在整個程序空間中,該類只存在一個實例對象。其實,GoF對單例模式的定義是:保證一個類、只有一個實例存在,同時提供能對該實例加以訪問的全局訪問方法。
最好創建的時候加上valatile防止指令重排序
public static Person4 getnewInstance() {
        if(person ==null){//提高效率
            synchronized (Person.class) {
                if(person == null)
                person = new Person4();
            }
        }
        return person;
    }

3.spring創建單例的模式

在spring的框架里,對象是交給spring容器創建的,spring的創建單例的方式既不是懶漢式也不是餓漢式,是單例注冊表模式實現單例模式的

https://blog.csdn.net/u012794505/article/details/80926823

4.spring中創建單線程在多線程中的安全問題

1.當多個用戶同時請求一個服務器時,容器(tomcat)會給每一個請求分配一個線程,這時多個線程會並發執行該請求所對應的業務邏輯(controller里的方法),此時就要注意啦,如果controller(是單例對象)里有全局變量並且又是可以修改的,那么就需要考慮線程安全的問題。
解決方案有很多,比如設置@scope("prototype")為多例模式,為每個線程創建一個controller,還可以使用ThreadLocal。
2.

2.其實spring的源碼里比如RequestContextHolder、TransactionSynchronizationManager、LoxaleContextHolder等這些對象創建方式也是單例,底層就是用ThreadLocal處理的。ThreadLocal基本實現思路是:它會為每個線程提供一個獨立的變量副本,從而隔離了多個線程對數據的訪問沖突,因為每個線程都擁有自己的變量副本,從而也就沒必要對該變量進行同步啦。

 5.多例 scope("prototype") 的時候位置不同,那么他被初始化和使用的時候也不一樣

   
   1  使用在controller層的情況下,他是在每次請求到該controller的時候,進行一個實例化,就是創建一個新的controller對象

 @PostConstruct
     public void init(){
        //此處每次有新的請求進來的時候,都會實例化一個新的controller對象
        System.out.println("ProductListController-->init:,this:"+this);
     }

   2  server層使用多例的注解,這個地方會出現很多的坑,這個也是我們需要特別注意的
  

  首先我們說在默認的單例情況下
    2.1  在controller層 使用@Autowired 來注入一個server層的實例
    2.1  此時spring容器為我們怎么處理的?
       2.1.1  在創建了一個server單實例后,在引入了該controller的地方,setter到該server的屬性上
         此時如果有3個或者n個controller同時 @Autowired Server 該server,那么這n個controller同時擁有同一個server對象
此時我們說下多例模式下
   1  controller層是單例
      server層使用多例模式
我們會發現,在三個controller層注入的server的實例是不一樣的。也就是體現了多例

  但是我們需要注意:server的多例是相對於每個不同引入的地方而言的
      其實我們會發現,在spring容器初始化的時候,他會為每一個controller中的server實例化一個對象,這個實例化對象,就被綁定到了這個controller上了,意思就是(如      論你有n多個請求,都請求到同一個controller上,此時這n個請求使用的server對象是同一個。),但是在不同的controller里的server是不一樣的。
      同理,如果我們的controller是prototype多例的,server也是多例的,這時候的情況和上面也是類似的controller多例 是在每次請求的時候創建一個新的實例,
    但是server不一樣,如果在controller里面,使用@Autowired server進行了注入,該server的實例並不會在每次請求到該位置的時候才進行實例化的,仍然是在spring容      器初始化的時候就一樣完成了對每個controller的注入

6.解決

  很多時候我們會在service中定義私有屬性,這些屬性會被作為該類的全局變量來使用,而且該屬性是一個動態賦值, 如果向上面那樣,雖然server在被多例后,在不同的controller類下具有不同的實例,但是,對於同一個controller類而言,他們持有同一個server對象,也就是該屬性是共享的,隨時可能被另外的請求給修改。這時候我們的server中的該屬性是非線程安全的。

  所以我們要想辦法,在每次請求的時候,都要獲取一個新的server實例,這樣才可以保證變量線程安全

    @Autowired
    ApplicationContent applicationContent;
    我們可以通過上下文容器在需要的時候主動去獲取,
    Server ser = applicationContent.getBean(Server.class);

https://gitee.com/Sxuxiaoyu/noteImages/raw/master/img/spring中的多例.png






免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM