Как заблокировать Java-метод для защиты нескольких вызовов - PullRequest
9 голосов
/ 12 марта 2010

У меня есть приложение, которое каждые 15 минут выполняет репликацию из удаленной базы данных. Он просто синхронизирует два хранилища. Как только эта репликация будет запущена, это невозможно сделать снова. Я настроил следующую структуру, но я не уверен, что это правильный подход.

public class ReplicatorRunner {

       private static Lock lock = new ReentrantLock();

       public replicate() {

           if (lock.tryLock()) {
               try {
                   // long running process
               } catch (Exception e) {                   
               } finally {
                   lock.unlock();
               }               
           } else {
               throw new IllegalStateException("already replicating");
           }

       }

}

public class ReplicatorRunnerInvocator {

    public void someMethod() {

        try {
            ReplicatorRunner replicator = new ReplicatorRunner();
            replicator.replicate();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        }

    }

}

ReplicatorRunner - это класс, которому принадлежит метод replicate, который можно запускать только по одному за раз.

Edit. Мне нужно, чтобы следующий вызов потерпел неудачу ( не блокируется ), если метод уже запущен на любом экземпляре.

Ответы [ 5 ]

4 голосов
/ 12 марта 2010

Это выглядит хорошо.ReentrantLock.tryLock () предоставит блокировку только одному потоку, поэтому synchronized не требуется.Это также предотвращает блокировку, присущую синхронизации, которая, как вы говорите, является обязательным требованием.ReentrantLock является Serializable, поэтому должен работать во всем кластере.

Перейти на это.

1 голос
/ 13 марта 2010

Я использовал следующее:

public class ReplicatorRunner {

       private static Semaphore lock = new Semaphore(1);

       public replicate() {

           if (lock.tryAcquire()) {
               try {                              
                   // basic setup                  
                   Thread t = new Thread(new Runnable() {
                       public void run() {
                           try {
                               // long running process                               
                           } catch Exception (e) {
                               // handle the exceptions
                           } finally {
                               lock.release();
                           }
                       }
                   })
                   t.start();

               } catch (Exception e) {
                   // in case something goes wrong
                   // before the thread starts
                   lock.release();
               }              
           } else {
               throw new IllegalStateException("already replicating");
           }

       }

}

public class ReplicatorRunnerInvocator {

    public void someMethod() {

        try {
            ReplicatorRunner replicator = new ReplicatorRunner();
            replicator.replicate();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        }

    }

}
1 голос
/ 12 марта 2010

Изменить public replicate() на public synchronized replicate()

Таким образом, репликация будет разрешать доступ только одному потоку за раз. Вы также сможете удалить ReentrantLock и весь связанный код.

0 голосов
/ 12 марта 2010

Не глядя на специфику ReentrantLock, мне приходит в голову, что это предотвращение нескольких процедур одновременной репликации будет ограничено одним экземпляром JVM.

Если другой экземпляр класса запускается в отдельной JVM, то у вас могут быть проблемы.

Почему бы не установить механизм блокировки базы данных? то есть строка в управляющей таблице, для которой установлено значение, показывающее, занята ли репликация или нет, и сбросьте значение после завершения репликации.

0 голосов
/ 12 марта 2010

взгляните на класс семафора здесь или пометьте метод как синхронизированный поток, выполняющий метод в любой момент времени, владеет блокировкой, позволяющей другим потокам вызывать метод до тех пор, пока не завершится его выполнение.
Редактировать: если вы хотите, чтобы другие потоки не работали, вы можете использовать Lock и проверить, доступна ли блокировка методом tryLock.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...