Как мне убедиться, что только один поток запускается

Ситуация в том, что я должен убедиться, что создается только один 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().

Другие вопросы по тегам