Замки между двумя способами, голодающие одним методом

В моей программе у меня есть два метода:

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();
    }
}

Ответ 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 не важна.