Servlet 容器為每個 Servlet 創建單例,多線程並發訪問同一實例。若 Servlet 使用實例變量保存請求狀態,將導致線程安全災難。本文演進從線程安全基礎到 Spring 聲明式事務的最佳實踐。
Hashtable、Vector 方法全同步,優先用 HashMap、ArrayList + 外部同步或並發包。// 非線程安全:共享實例變量
private Double pi = null;
public Double pi() {
if (pi == null) pi = new Double(22/7); // 競態條件
return pi;
}
// 線程安全 + 高性能:ThreadLocal
private static final ThreadLocal pi = new ThreadLocal<>();
public Double pi() {
if (pi.get() == null) pi.set(new Double(22/7));
return pi.get();
}
每個線程獨享副本,無競爭、無阻塞。JDK 1.4+ 優化了 ThreadLocal 性能,生產可用。
JDBC Connection、Statement、Hibernate Session 均為有狀態、非線程安全對象,不能跨線程共享。
傳統做法:Filter 創建連接/Session 綁定 ThreadLocal,業務層獲取使用,請求結束清理。缺點:樣板代碼多、事務管理分散、異常處理繁瑣。
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingDirectoryLocations">
<list><value>classpath:</value></list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">net.sf.hibernate.dialect.HSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
public interface CustomerDAO {
void createCustomer(Customer customer);
}
public class HibernateCustomerDAO implements CustomerDAO {
private HibernateTemplate hibernateTemplate;
public void setSessionFactory(SessionFactory sf) {
this.hibernateTemplate = new HibernateTemplate(sf, false); // false=不允許創建新 Session
}
public void createCustomer(Customer customer) {
hibernateTemplate.save(customer); // 自動參與綁定到線程的 Session
}
}
HibernateTemplate 線程安全(無實例狀態),封裝異常轉換、資源清理、最佳實踐。
<bean id="transactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="customerDAO" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager"/>
<property name="target" ref="customerDAOTarget"/>
<property name="transactionAttributes">
<props>
<prop key="create*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
createCustomer()。TransactionProxyFactoryBean 攔截,委託 HibernateTransactionManager。ThreadLocal 是否綁定 Session:
ThreadLocal,開啟事務。HibernateTemplate.save(),自動使用綁定 Session。Spring 通過 ThreadLocal 綁定資源 + 模板封裝最佳實踐 + AOP 聲明式事務,實現了:
這是企業級 Spring 應用線程安全的標準架構。