科技报道|一次性搞清楚,Java并发编程在各主流框架中的应用,保证看懂( 四 )


/** * 管理每个线程的资源和事务同步的中心帮助程序 。 供资源管理代码使用 , 但不供典型应用程序代码使用 。* * 资源管理代码应该检查线程绑定的资源 , 如 , JDBC连接 或 Hibernate Sessions 。* 此类代码通常不应该将资源绑定到线程 , 因为这是事务管理器的职责 。 另一个选项是 ,* 如果事务同步处于活动状态 , 则在首次使用时延迟绑定 , 以执行跨任意数量资源的事务 。*/public abstract class TransactionSynchronizationManager {/***一般是一个线程持有一个 独立的事务 , 以相互隔离地处理各自的事务 。*所以这里使用了很多 ThreadLocal对象 , 为每个线程绑定 对应的事务属性及资源 ,*以便后续使用时能直接获取 。*/private static final ThreadLocal> resources =new NamedThreadLocal>("Transactional resources");private static final ThreadLocal synchronizations =new NamedThreadLocal("Transaction synchronizations");private static final ThreadLocal currentTransactionName =new NamedThreadLocal("Current transaction name");private static final ThreadLocal currentTransactionReadOnly =new NamedThreadLocal("Current transaction read-only status");private static final ThreadLocal currentTransactionIsolationLevel =new NamedThreadLocal("Current transaction isolation level");private static final ThreadLocal actualTransactionActive =new NamedThreadLocal("Actual transaction active");/*** 为当前线程 绑定 对应的resource资源*/public static void bindResource(Object key, Object value) throws IllegalStateException {Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);Assert.notNull(value, "Value must not be null");Map map = resources.get();// 如果当前线程的 resources中 , 绑定的数据map为空 , 则为 resources 绑定 mapif (map == null) {map = new HashMap();resources.set(map);}Object oldValue = http://kandian.youth.cn/index/map.put(actualKey, value);if (oldValue instanceof ResourceHolder}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 Map getResourceMap() {Map map = resources.get();return (map != null ? Collections.unmodifiableMap(map) : Collections.emptyMap());}}ThreadLocal 在 Mybatis 中的使用
Mybatis 的 SqlSession 对象 也是各线程私有的资源 , 所以对其的管理也使用到了 ThreadLocal 类 。 源码如下 。
public class SqlSessionManager implements SqlSessionFactory, SqlSession {private final ThreadLocal localSqlSession = new ThreadLocal<>();public void startManagedSession() {this.localSqlSession.set(openSession());}public void startManagedSession(boolean autoCommit) {this.localSqlSession.set(openSession(autoCommit));}public void startManagedSession(Connection connection) {this.localSqlSession.set(openSession(connection));}public void startManagedSession(TransactionIsolationLevel level) {this.localSqlSession.set(openSession(level));}public void startManagedSession(ExecutorType execType) {this.localSqlSession.set(openSession(execType));}public void startManagedSession(ExecutorType execType, boolean autoCommit) {this.localSqlSession.set(openSession(execType, autoCommit));}public void startManagedSession(ExecutorType execType, TransactionIsolationLevel level) {this.localSqlSession.set(openSession(execType, level));}public void startManagedSession(ExecutorType execType, Connection connection) {this.localSqlSession.set(openSession(execType, connection));}public boolean isManagedSessionStarted() {return this.localSqlSession.get() != null;}@Overridepublic Connection getConnection() {final SqlSession sqlSession = localSqlSession.get();if (sqlSession == null) {throw new SqlSessionException("Error:Cannot get connection.No managed session is started.");}return sqlSession.getConnection();}@Overridepublic void clearCache() {final SqlSession sqlSession = localSqlSession.get();if (sqlSession == null) {throw new SqlSessionException("Error:Cannot clear the cache.No managed session is started.");}sqlSession.clearCache();}@Overridepublic void commit() {final SqlSession sqlSession = localSqlSession.get();if (sqlSession == null) {throw new SqlSessionException("Error:Cannot commit.No managed session is started.");}sqlSession.commit();}@Overridepublic void commit(boolean force) {final SqlSession sqlSession = localSqlSession.get();if (sqlSession == null) {throw new SqlSessionException("Error:Cannot commit.No managed session is started.");}sqlSession.commit(force);}@Overridepublic void rollback() {final SqlSession sqlSession = localSqlSession.get();if (sqlSession == null) {throw new SqlSessionException("Error:Cannot rollback.No managed session is started.");}sqlSession.rollback();}@Overridepublic void rollback(boolean force) {final SqlSession sqlSession = localSqlSession.get();if (sqlSession == null) {throw new SqlSessionException("Error:Cannot rollback.No managed session is started.");}sqlSession.rollback(force);}@Overridepublic List flushStatements() {final SqlSession sqlSession = localSqlSession.get();if (sqlSession == null) {throw new SqlSessionException("Error:Cannot rollback.No managed session is started.");}return sqlSession.flushStatements();}@Overridepublic void close() {final SqlSession sqlSession = localSqlSession.get();if (sqlSession == null) {throw new SqlSessionException("Error:Cannot close.No managed session is started.");}try {sqlSession.close();} finally {localSqlSession.set(null);}}}


推荐阅读