在我们编程时,如果遇到多个线程访问同一个变量应该怎样实现?有人说使用同步。是的同步可以解决这种问题,但它是有弊端的,涉及到何时加锁与释放锁等并且线程访问锁时需要等待,这样很浪费时间。有一个更好的方案就是使用ThreadLocal工具类,之前参加了一个项目,本项目涉及到分库,在业务进行中需要根据唯一的ID去定位数据源然后做一系列的操作。
ThreadLocal不是用来解决共享资源的多线程访问的问题, hreadLocal的set()方法设置到线程的ThreadLocal.ThreadLocalMap里的是线程自己要存储的对象,其他线程访问不到。各个线程中的ThreadLocal.ThreadLocalMap以及ThreadLocal.ThreadLocal中的值都是不同的对象。
下面看一下定位与设置数据源的工具类
/**
* 在ThreadLocal中保存当前线程需要使用的String。
*
* @author wangzuojia
*/
public class DataSourceContextHolder {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
public static void setDataSource(String type) {
// 不使用mycat时这里切换数据源的地方进行屏蔽
contextHolder.set(type);
}
public static String determineCurrentLookupKey() {
String dbtype = (String)contextHolder.get();
return dbtype;
}
public static String getDataSource() {
String dbtype = (String)contextHolder.get();
if(dbtype == null ){
//获取默认数据源
dbtype = getDefaultDataSource();
}
return dbtype;
}
public static String getDefaultDataSource() {
//获取默认数据源
String defaultDbtype = (String) SpringContextHolder.getBean("defaultDbtype");
defaultDbtype = defaultDbtype.trim();
//logger.info("defaultDatasource:"+defaultDbtype);
return defaultDbtype;
}
public static void clearString() {
contextHolder.remove();
}
}
下面看一下如何使用获取数据源的工具类
public static void updateTIdMappingStatus(String id,String tablename,String key1,String key2,String key3,String key4,String oldstatus,String status){
TIdmappingService tIdmappingService = SpringContextHolder.getBean(TIdmappingService.class);
// 获取正在使用的dbtype
String oldDbtype = DataSourceContextHolder.getDataSource();
try {
DataSourceContextHolder.setDataSource(DatasourceSpiltUtil.dbtype_default);
tIdmappingService.updateTIdMappingStatus( id, tablename, key1, key2, null, null, oldstatus, status);
} finally {
// 还原正在使用的dbtype
if (oldDbtype != null) {
DataSourceContextHolder.setDataSource(oldDbtype);
}
}
}
这样多线程在访问数据源时,就可以做到互不干扰。