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); }
相关文章
相关标签/搜索