1. 程式人生 > >spring 單例 併發訪問

spring 單例 併發訪問

一、TOMCAT 併發請求

1、tomcat模式有 BIO、NIO、APR三種模式,作業系統對程序的執行緒數有限制,Windows:2000,linux:1000;Tomcat預設配置的最大請求數是150,[即150個bio執行緒],遠超過150的最好就採取叢集

2、BIO模式,即阻塞IO,預設配置。

         server.xml:<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />

         每個請求都需要建立一個執行緒進行處理,這種模式下的併發量受到執行緒數量的限制,勝在模式成熟穩定,BUG極少

3、NIO模式,即非阻塞IO,JAVA NIO實現理論基礎,實現較複雜,[建議可採用netty框架來快速實現]

         server.xml:<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol" connectionTimeout="20000" redirectPort="8443" />

        在效能上高於阻塞式的,每個請求也不用額外建立一個新執行緒進行處理,併發能力能BIO強;適用於連線數目多且連線比較短(輕操作)的架構,比如聊天伺服器,併發侷限於應用中,程式設計比較複雜

4、APR模式,(Apache Portable Runtime/Apache可移植執行庫),是Apache HTTP伺服器的支援庫。當然,apr模式還需要安裝 apr 、 apr-utils 、tomcat-native包

        server.xml:<Connector port="8080" protocol="org.apache.coyote.http11.Http11AprProtocol" connectionTimeout="20000" redirectPort="8443" />,

        Tomcat將以JNI的形式呼叫Apache HTTP伺服器的核心動態連結庫來處理檔案讀取或網路傳輸操作,從而大大地提高Tomcat對靜態檔案的處理效能。 Tomcat apr也是在Tomcat上執行高併發應用的首選模式。

===========分割線,bio執行緒是池模式複用的,所以一個bio執行緒可以承載多次request請求==========================

二、spring 單例 @controller、@service

        1、spring框架controller和service預設都是單例的,那麼多併發bio時,是如何實現執行緒安全的?    執行緒與棧:

             A、每當啟用一個執行緒時,JVM就為他分配一個Java棧,棧是以幀為單位儲存當前執行緒的執行狀態。某個執行緒正在執行的方法稱為當前方法,當前方法使用的棧幀稱為當前幀,當前方法所屬的類稱為當前類,當前類的常量稱為當前常量池。當執行緒執行一個方法時,它會跟蹤當前常量池。
             B、每當執行緒呼叫一個Java方法時,JVM就會在該執行緒對應的棧中壓入一個幀,這個幀自然就成了當前幀。當執行這個方法時,它使用這個幀來儲存引數、區域性變數、中間運算結果等等。
             C、Java棧上的所有資料都是私有的。任何執行緒都不能訪問另一個執行緒的棧資料。所以我們不用考慮多執行緒情況下棧資料訪問同步的情況。

             D、如上,則@Controller是單例模式,即一個物件只有一個例項。通過執行緒副本[棧]的模式實現併發訪問

        2、執行緒副本與安全問題  執行緒副本通過棧和幀實現執行緒隔離,達到併發訪問的目的,那麼有沒有前提呢?

            A、如上二-1-B所述,區域性變數和中間運算結果集引數是執行緒隔離==>安全的,但是成員變數則是會受到多執行緒呼叫影響的

            B、那Controller裡面的service都是成員變數,會受影響麼?service也是單例,其主要用來實現方法呼叫,就會進入幀的切換從而轉變為中間結果的問題,同理單例的service的成員變數和區域性變數的執行緒隔離性同Controller。

                PS:Spring對一些Bean(如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等)中非執行緒安全狀態採用ThreadLocal進行處理,讓它們也成為執行緒安全的狀態。

                        https://my.oschina.net/ysma1987/blog/2885611 記錄了AOP切面中獲取request方式的原理就是據此而來

                        TransactionSynchronizationManager對資源resources採用ThreadLocal保管,就是dao的SqlSession[亦即getConnection]的由來

            C、對應的成員變數就被暴露在所有執行緒面前了,所以最好用ThreadLocal保護起來,實現執行緒安全。

                 PS:https://my.oschina.net/ysma1987/blog/3034499 描述了ThreadLocal在此種模式下的坑

三、單例應用場景

            A、有狀態和無狀態的物件基本概念: 

                    有狀態物件(Stateful Bean),就是有例項變數的物件 ,可以儲存資料,是非執行緒安全的。一般是prototype scope。

                    無狀態物件(Stateless Bean),就是沒有例項變數的物件,不能儲存資料,是不變類,是執行緒安全的。一般是singleton scope。

                    Service和Dao就都是無狀態物件,適用於單例場景,如果有資源操作的限制,就涉及同步器、鎖等操作了

三、多執行緒與事務的藕斷絲連

                事務管理器用於管理各個事務方法,它產生一個事務管理上下文。下文以SpringJDBC的事務管理器DataSourceTransactionManager類為例

                spring七個事務傳播屬性[PROPAGATION_REQUIRED等]和五個隔離級別[ISOLATION_DEFAULT 等]

                 我們知道資料庫連線Connection在不同執行緒中是不能共享的,事務管理器為不同的事務執行緒利用ThreadLocal類提供獨立的Connection副本。事實上,它將Service和Dao中所有執行緒不安全的變數都提取出來單獨放在一個地方,並用ThreadLocal替換。而多執行緒可以共享的部分則以單例項方式存在。

                延伸問:事務個預設隔離屬性和和預設傳播屬性是什麼?以及在多執行緒中的影響?

========================分割線===================================

參考文件:https://blog.csdn.net/liumohan0806/article/details/72723205

                https://blog.csdn.net/qq_41173453/article/details/81195997

                https://blog.csdn.net/mrleeapple/article/details/80420395

                https://2277259257.iteye.com/blog/2300298

                https://blog.csdn.net/baidu_37107022/article/details