情况是,我必须确保当我尝试getConnection时只创建一个RecoveryThread,如果它在PrimaryData Source上的getConnection失败,那么我的代码是:
public Connection getConnection() throws SQLException {
if (isFailedOver()) {
try {
return failoverDataSource.getConnection();
} catch (SQLException e) {
throwBigError();
}
}
Connection connection = null;
try {
connection = dataSource.getConnection();
return connection;
}
catch (SQLException unexpected) {
return requestFailover();
}
}
private Connection requestFailover() throws SQLException {
this.dbFailoverMutex.requestFailover();
DBFailoverRecoveryService recoveryService = new DBFailoverRecoveryService(this.dbFailoverMutex,this.dataSource);
Thread recoveryServiceThread = new Thread(recoveryService, "DBFailover Recovery Service");
recoveryServiceThread.start();
try {
return failoverDataSource.getConnection();
} catch (SQLException e) {
throwBigError();
}
return null;
}
如果有两个不同的线程尝试getConnection,这可能最终调用requestFailover()方法两次,当它被调用两次时,这将最终创建两个recoveryService线程,我该怎么做以确保永远不会发生?
提前感谢您的帮助。
答案 0 :(得分:5)
我该怎么做以确保永远不会发生?
要考虑的一件事是切换到使用Executors.newSingleThreadExecutor()
,它只会分叉一个线程来运行。然后,您可以根据需要提交任意数量的任务,而无需担心它们重叠。
private final ExecutorService threadPool =
Executors.newSingleThreadExecutor(/* pass in ThreadFactory to set name */);
...
DBFailoverRecoveryService recoveryService =
new DBFailoverRecoveryService(this.dbFailoverMutex, this.dataSource);
threadPool.submit(recoveryService);
与ExecutorService
一样,您需要在将最后一项任务提交到池后调用threadPool.shutdown()
,否则会挂起您的应用程序。您可以添加Datasource.destroy();
方法来执行此操作。
答案 1 :(得分:0)
您可以将“synchronized”修饰符添加到getConnection方法,然后添加一个布尔标志来指示是否已经请求了故障转移,例如
public synchronized getConnection(){ throws SQLException
if(alreadyRequestedFailover){
return;
}
....
catch (SQLException unexpected) {
alreadyRequestedFailover = true;
return requestFailover();
}
}
这将阻止两个线程同时进入getConnection()方法,并确保如果线程请求故障转移,它将在允许另一个线程进入getConnection()之前更新alreadyRequestedFailover标志。