0

我正在做一个项目,其中我在不同的数据库中有两个具有不同模式的表。所以这意味着我有两个不同的连接参数让这两个表使用 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存储两个不同的数据库连接。然后我有一个tableStatementas ConcurrentHashMap ,我在其中存储ReadTableConnectionInfo对象dbConnection。例如 Table1 对象将在tableStatementConcurrentHashMap 中有 Table1 连接。

问题陈述:-

我想看看thread safety issues在我的运行方法中是否有任何潜在的可能性,我在tableStatementConcurrentHashMap 中插入的方式或任何其他线程安全问题?

4

1 回答 1

0

您的任务类不在线程之间共享(在您当前的示例中),因此在访问对象内部状态时没有并发问题。目前,您的任务的每个实例只能在执行程序分配给它的线程中访问:

service.submit(new ReadTask(tableList));

使用上面的代码行,您实例化了一个实例ReadTask并要求执行程序在单独的线程中运行它。如果您不在任何其他线程中访问该对象,那么您就没有并发问题。

实际上,在您的示例中,您不需要使用并发哈希映射(因为您没有为外部对象提供任何方式来修改该集合)。

如果您想做任何事情来修改您的代码,请考虑使ReadTableConnectionInfo对象不可变。您可以通过以下方式做到这一点:

  • 将每个类实例变量声明为 final。
  • 提供一个构造函数,该构造函数接受每个实例变量的值
  • 删除类setter方法
  • readPropertyFile在您的方法中使用新的构造函数。
于 2013-02-26T03:10:16.020 回答