Spring Bean的線程安全

         Spring 的 bean 做用域(scope)類型java

         一、singleton:單例,默認做用域。安全

         二、prototype:原型,每次建立一個新對象。session

         三、request:請求,每次Http請求建立一個新對象,適用於WebApplicationContext環境下。多線程

         四、session:會話,同一個會話共享一個實例,不一樣會話使用不用的實例。併發

         五、global-session:全局會話,全部會話共享一個實例。mvc

 

         線程安全這個問題,要從單例與原型Bean分別進行說明。ide

 

         單例singletonBean:全部線程都共享一個單例實例Bean,所以是存在資源的競爭, 若是單例Bean,是一個無狀態Bean,也就是線程中的操做不會對Bean的成員執行查詢之外的操做,那麼這個單例Bean是線程安全的。好比Spring mvc 的 Controller、Service、Dao等,這些Bean大可能是無狀態的,只關注於方法自己高併發

         原型(prototype)Bean:每次建立一個新對象,也就是線程之間並不存在Bean共享,天然是不會有線程安全的問題。
spa

         對於有狀態的bean,Spring官方提供的bean,通常提供了經過ThreadLocal去解決線程安全的方法,好比RequestContextHolderTransactionSynchronizationManagerLocaleContextHolder等,使用ThreadLocal的好處 使得多線程場景下,多個線程對這個單例Bean的成員變量並不存在資源的競爭,由於ThreadLocal爲每一個線程保存線程私有的數據。這是一種以空間換時間的方式。固然也能夠經過加鎖的方法來解決線程安全,這種以時間換空間的場景在高併發場景下顯然是不實際的。prototype

 

          下面分析下經過TreadLocal解決線程安全的三個類:

RequestContextHolder 代碼演示

ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes(); //獲取HttpServletRequest
HttpServletRequest request = requestAttributes.getRequest();

RequestContextHolder 部分源碼

public abstract class RequestContextHolder { private static final boolean jsfPresent = ClassUtils.isPresent("javax.faces.context.FacesContext", RequestContextHolder.class.getClassLoader()); private static final ThreadLocal<RequestAttributes> requestAttributesHolder = new NamedThreadLocal("Request attributes"); private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder = new NamedInheritableThreadLocal("Request context"); public RequestContextHolder() { } ------------------------------------省略部分代碼----------------------------------- @Nullable public static RequestAttributes getRequestAttributes() { RequestAttributes attributes = (RequestAttributes)requestAttributesHolder.get(); if (attributes == null) { attributes = (RequestAttributes)inheritableRequestAttributesHolder.get(); } return attributes; } ------------------------------------省略部分代碼-----------------------------------

 

LocaleContextHolder  代碼演示

Locale locale = LocaleContextHolder.getLocale(); System.out.println(locale.toString());//語言

LocaleContextHolder 部分源碼

public final class LocaleContextHolder { private static final ThreadLocal<LocaleContext> localeContextHolder =
            new NamedThreadLocal<>("LocaleContext"); private static final ThreadLocal<LocaleContext> inheritableLocaleContextHolder =
            new NamedInheritableThreadLocal<>("LocaleContext"); // Shared default locale at the framework level
 @Nullable private static Locale defaultLocale; // Shared default time zone at the framework level
 @Nullable private static TimeZone defaultTimeZone; ------------------------------------省略部分代碼-----------------------------------
            
public static Locale getLocale() { return getLocale(getLocaleContext()); } ------------------------------------省略部分代碼----------------------------------- @Nullable public static LocaleContext getLocaleContext() { LocaleContext localeContext = localeContextHolder.get(); if (localeContext == null) { localeContext = inheritableLocaleContextHolder.get(); } return localeContext; } ------------------------------------省略部分代碼-----------------------------------

 

TransactionSynchronizationManager 代碼演示

@Transactional public void doInTransaction() { TransactionSynchronizationManager.bindResource("key", "value");//ThreadLocal維護
 TransactionSynchronizationManager.registerSynchronization (new TransactionSynchronizationAdapter() { @Override public void afterCommit() { System.out.println("transaction commit"); } }); }
TransactionSynchronizationManager 部分源碼
public abstract class TransactionSynchronizationManager { private static final Log logger = LogFactory.getLog(TransactionSynchronizationManager.class); private static final ThreadLocal<Map<Object, Object>> resources =
         new NamedThreadLocal<>("Transactional resources"); private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
         new NamedThreadLocal<>("Transaction synchronizations"); private static final ThreadLocal<String> currentTransactionName =
         new NamedThreadLocal<>("Current transaction name"); private static final ThreadLocal<Boolean> currentTransactionReadOnly =
         new NamedThreadLocal<>("Current transaction read-only status"); private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
         new NamedThreadLocal<>("Current transaction isolation level"); private static final ThreadLocal<Boolean> actualTransactionActive =
         new NamedThreadLocal<>("Actual transaction active"); ------------------------------------省略部分代碼-----------------------------------
    
public static void bindResource(Object key, Object value) throws IllegalStateException { Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key); Assert.notNull(value, "Value must not be null"); Map<Object, Object> map = resources.get(); // set ThreadLocal Map if none found
    if (map == null) { map = new HashMap<>(); resources.set(map); } Object oldValue = map.put(actualKey, value); // Transparently suppress a ResourceHolder that was marked as void...
    if (oldValue instanceof ResourceHolder && ((ResourceHolder) oldValue).isVoid()) { oldValue = null; } if (oldValue != null) { throw new IllegalStateException("Already value [" + oldValue + "] for key [" + actualKey + "] bound to thread [" + Thread.currentThread().getName() + "]"); } if (logger.isTraceEnabled()) { logger.trace("Bound value [" + value + "] for key [" + actualKey + "] to thread [" + Thread.currentThread().getName() + "]"); } } ------------------------------------省略部分代碼-----------------------------------
        
    public static void registerSynchronization(TransactionSynchronization synchronization) throws IllegalStateException { Assert.notNull(synchronization, "TransactionSynchronization must not be null"); if (!isSynchronizationActive()) { throw new IllegalStateException("Transaction synchronization is not active"); } synchronizations.get().add(synchronization); }
相關文章
相關標籤/搜索