我正在开发一个项目,其中我在具有不同模式的不同数据库中有两个表。这意味着我有两个不同的连接参数,用于使用JDBC连接这两个表 -
我们假设下面是config.property文件 -
TABLES: table1 table2
#For Table1
table1.url: jdbc:mysql://localhost:3306/garden
table1.user: gardener
table1.password: shavel
table1.driver: jdbc-driver
#For Table2
table2.url: jdbc:mysql://otherhost:3306/forest
table2.user: forester
table2.password: axe
table2.driver: jdbc-driver
下面的方法将阅读上面的config.properties
文件并为每个表创建一个ReadTableConnectionInfo
对象。
private static void readPropertyFile() throws IOException {
prop.load(Read.class.getClassLoader().getResourceAsStream("config.properties"));
tableNames = Arrays.asList(prop.getProperty("TABLES").split(" "));
for (String arg : tableNames) {
ReadTableConnectionInfo ci = new ReadTableConnectionInfo();
String url = prop.getProperty(arg + ".url");
String user = prop.getProperty(arg + ".user");
String password = prop.getProperty(arg + ".password");
String driver = prop.getProperty(arg + ".driver");
ci.setUrl(url);
ci.setUser(user);
ci.setPassword(password);
ci.setDriver(driver);
tableList.put(arg, ci);
}
}
以下是ReadTableConnectionInfo class
,其中包含特定表格的所有table connection info
。
public class ReadTableConnectionInfo {
public String url;
public String user;
public String password;
public String driver;
public String percentage;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getDriver() {
return driver;
}
public void setDriver(String driver) {
this.driver = driver;
}
}
现在我正在为指定数量的线程创建ExecutorService
并将此tableList
对象(我通过阅读config.property file
创建)传递给ReadTask class
的构造函数 -
// create thread pool with given size
ExecutorService service = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
service.submit(new ReadTask(tableList));
}
下面是我的ReadTask
类,它实现了Runnable interface
,其中每个线程在执行任何有意义的操作之前为每个表创建两个连接。
class ReadTask implements Runnable {
private Connection[] dbConnection = null;
private ConcurrentHashMap<ReadTableConnectionInfo, Connection> tableStatement = new ConcurrentHashMap<ReadTableConnectionInfo, Connection>();
public ReadTask(LinkedHashMap<String, XMPReadTableConnectionInfo> tableList) {
this.tableLists = tableList;
}
@Override
public void run() {
try {
int j = 0;
dbConnection = new Connection[tableList.size()];
//loop around the map values and make the connection list
for (ReadTableConnectionInfo ci : tableList.values()) {
dbConnection[j] = getDBConnection(ci.getUrl(), ci.getUser(), ci.getPassword(), ci.getDriver());
tableStatement.putIfAbsent(ci, dbConnection[j]);
j++;
}
//do other meaningful thing here
}
}
}
在我上面的try块中,我正在创建dbConnection array
来存储两个不同的数据库连接。然后我有一个tableStatement
作为ConcurrentHashMap,我在其中存储ReadTableConnectionInfo
对象的dbConnection
。例如,Table1对象将在tableStatement
ConcurrentHashMap中具有Table1连接。
问题陈述: -
我正在尝试使用我在thread safety issues
ConcurrentHashMap中插入的方式或其他任何线程安全问题来查看我的run方法中是否存在任何潜在的tableStatement
?
答案 0 :(得分:0)
您的任务类不在线程之间共享(在当前示例中),因此在访问对象内部状态时没有并发问题。目前,您的任务的每个实例仅在执行程序分配给它的线程中访问:
service.submit(new ReadTask(tableList));
使用上面的代码行,您实例化ReadTask
的实例并要求执行程序在单独的线程中运行它。如果您没有访问任何其他线程中的对象,那么您就没有并发问题。
在您的示例中,实际上,您不需要使用并发哈希映射(因为您没有为外部对象提供任何修改该集合的方法)。
如果要执行任何操作来修改代码,请考虑使ReadTableConnectionInfo
对象不可变。您可以通过以下方式执行此操作:
setter
方法readPropertyFile
方法中使用新构造函数。