Как мне убедиться, что только один поток запускается
Ситуация в том, что я должен убедиться, что создается только один RecoveryThread, когда я пытаюсь получить getConnection, и если он не работает на getConnection на PrimaryData Source, происходит сбой. Код, который я имею:
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, что я могу сделать, чтобы убедиться, что этого никогда не произойдет?
Заранее спасибо за помощь.
2 ответа
что я могу сделать, чтобы этого никогда не случилось?
Одна вещь, чтобы рассмотреть, это переключиться на использование 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();
способ сделать это.
Вы можете добавить модификатор "synchronized" в ваш метод getConnection, а затем добавить логический флаг, чтобы указать, был ли уже запрошен переход на другой ресурс, например
public synchronized getConnection(){ throws SQLException
if(alreadyRequestedFailover){
return;
}
....
catch (SQLException unexpected) {
alreadyRequestedFailover = true;
return requestFailover();
}
}
Это предотвратит одновременный вход двух потоков в метод getConnection() и гарантирует, что, если поток запросит аварийное переключение, он обновит флаг Уже RequestedFailover, прежде чем разрешить другой поток в getConnection().