У меня есть приложение что каждые 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
который может только быть выполнен по одному.
Править. Мне нужен следующий вызов для сбоя (не блок), если метод уже работает на каком-либо экземпляре.
Выглядит хорошо. ReentrantLock.tryLock () предоставит блокировку только одному потоку, поэтому synchronized
не требуется. Это также предотвращает блокировку, присущую синхронизации, которая, по вашему мнению, является обязательной. ReentrantLock поддерживает сериализацию, поэтому должен работать во всем кластере.
Дерзайте.
взгляните на класс Semaphore здесь или отметьте метод как синхронизированный {{1} } поток, выполняющий метод в любой момент времени, владеет блокировкой на нем, избегая того, чтобы другие потоки вызывали метод, пока его выполнение не закончится.
Изменить: если вы хотите, чтобы другие потоки завершились с ошибкой , вы можете использовать Блокировку и проверить, доступна ли блокировка с помощью метода tryLock.
Измените public replicate ()
на public synchronized replicate ()
Таким образом, при репликации будет разрешен доступ только к по одному потоку за раз. Вы также сможете удалить ReentrantLock и весь связанный с ним код.
В итоге я использовал следующее:
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();
}
}
}
Не вдаваясь в подробности ReentrantLock, мне приходит в голову, что это предотвращение нескольких подпрограмм одновременной репликации будет ограничено одним экземпляром JVM.
Если другой экземпляр класса запускается в отдельной JVM, у вас могут быть проблемы.
Почему бы не установить механизм блокировки для базы данных? т.е. строка в контрольной таблице, для которой установлено значение, показывающее, занята ли репликация, и сбрасывающее значение, когда репликация завершена.