Замки между двумя способами, голодающие одним методом
В моей программе у меня есть два метода:
public void methodA() { //gets called very often
//write something to file
}
public void methodB() {
//write something to file
}
methodA
часто вызывается клиентом, а methodB
время от времени вызывается только. Тем не менее, мне нужно убедиться, что всякий раз, когда клиент хочет вызвать methodB
, он может это сделать (после завершения текущего выполнения methodA
). Я попытался ввести синхронизированный блок с объектом блокировки в каждом методе, однако methodB
, похоже, голодает, так как methodA
получает вызов чаще.
Как я могу решить эту проблему?
Ответы
Ответ 1
Похоже, вам нужна справедливая Lock
. Чтобы сделать один из них, вы должны передать true
в качестве параметра конструктору.
Lock lock = new ReentrantLock(true);
public void methodA() {
lock.lock();
try {
// Write something to a file.
} finally {
lock.unlock();
}
}
public void methodB() {
lock.lock();
try {
// Write something to a file.
} finally {
lock.unlock();
}
}
Ответ 2
ReentrantLock
имеет конструктор с параметром справедливости, который должен предотвращать голодание в вашем случае.
Ответ 3
Если вы хотите определить приоритет метода B по методу A, это самая простая вещь, которую я мог бы придумать:
private Object writeLock = new Object();
private Object highPriorityLock = new Object();
private int highPriorityLockReleaseCount = 0;
private int highPriorityLockLockCount = 0;
public void methodA() {
synchronized (writeLock) {
synchronized (highPriorityLock) {
// Wait until there are no more highPriorityLocks
while (highPriorityLockLockCount != highPriorityLockReleaseCount) {
highPriorityLock.wait();
}
}
// Do write (thread holds write lock)
}
}
public void methodB() {
synchronized (highPriorityLock) {
// Get current lock count
int lockCount = highPriorityLockLockCount;
// Increment lock count by one
highPriorityLockLockCount++;
// Wait until lock is acquired (current release count reaches saved lock count)
while (lockCount != highPriorityLockReleaseCount) {
highPriorityLock.wait();
}
}
synchronized (writeLock) {
// Do write (thread holds write lock)
}
synchronized (highPriorityLock) {
// Relase high priority lock by incrementing current counter
highPriorityLockReleaseCount++;
highPriorityLock.notifyAll();
}
}
Обязательно обрабатывайте исключения и убедитесь, что блокировка с высоким приоритетом всегда правильно отлажена
Ответ 4
Я предлагаю включить приоритет в очередь. Просто две очереди, одна для метода А и другая для метода Б. Другой поток, работающий в очереди в логике ниже: когда очередь для B не пуста, оперируйте ее, в противном случае выполните очередь для A.
Ответ 5
Вы можете использовать semaphores для этого. Это в основном работает над тем, что вы устанавливаете поле в какое-то значение. Скажем, заблокировано. и по другому методу вы делаете какое-то время, которое повторяется бесконечно до завершения другого процесса. Вы можете использовать семафоры, вызывая метод в diffirent thread.. и используйте ключевое слово synchronized void..
Семафоры - частично частично программные решения. Существуют также чистые программные решения. например алгоритм Петерсона
Ответ 6
Если ваша главная проблема заключается в том, что вызов methodB
не должен быть заблокирован или голоден, вы можете разрешить параллельные проблемы с помощью неблокирующих операций ввода-вывода.
Java NIO.2 java.nio.channels.AsynchronousFileChannel может обеспечить такие потребности. Вы можете найти хорошее объяснение использования и пример здесь.
Ответ 7
Это примерно то же самое, что этот вопрос. Самый рейтинговый ответ на этот вопрос дает три варианта. Варианты 2 и 3 предполагают, что methodB
всегда будет вызываться из того же потока, о котором вы уже не говорили, но вариант 1 должен работать. Вариант 1, портированный на Java:
private final Lock m = new ReentrantLock();
private final Lock n = new ReentrantLock();
private final Lock l = new ReentrantLock();
public void methodA() {
l.lock();
n.lock();
m.lock();
n.unlock();
try {
doA();
} finally {
m.unlock();
l.unlock();
}
}
public void methodB() {
n.lock();
m.lock();
n.unlock();
try {
doB();
} finally {
m.unlock();
}
}
Это дает абсолютный приоритет methodB над методом A, в отличие от ответа OldCurmudgeon, который дает равный приоритет. Если вы также хотите, чтобы алгоритм был справедливым (помимо приоритета methodB
над methodA
), вы должны сделать блокировки n
и l
fair. Справедливость m
не важна.