Java оптимизировал чтение / запись общего ресурса / места в памяти без Atomic API, например AtomicInteger - PullRequest
1 голос
/ 01 июля 2019

Существует общий ресурс, и нам нужно выполнить операции чтения / записи, как показано ниже:

  1. Когда происходит запись в ресурс, чтение запрещается.
  2. Когда происходит чтение, запись запрещается, но чтение может выполняться несколькими потоками.

Я написал код, подобный указанному ниже, но проблема этого кода в том, что все чтения будут заблокированы, когда один поток чтения получит блокировку. Далее я думаю использовать логический флаг, например canReadContinue. Теперь, когда read впервые получает блокировку, я переключаю этот флаг на true, и если он равен true, другие потоки не должны пытаться получить блокировку.

class SharedResource {

    Lock writeLock

    public Object read() {
        writeLock.acquire()
        doRead()

    }

    public void write(Object toBeWritten) {
        writeLock.acquire()

        doWrite(toBeWritten)

        writeLock.release()
    }

}

Ожидается, что несколько потоков смогут читать, когда запись не ведется.

ОБНОВЛЕНО 1:

открытый класс SharedResource {

private Object writeLock = new Object();
private volatile boolean canReadContinue;
private volatile int readCount;

public void write(Object newState) throws InterruptedException {
    synchronized (writeLock) {
        // To make sure no read is going on
        while (readCount > 0) {
            wait();
        }
        System.out.println("Write thread has the lock.");
        doWrite(newState);
    }
}

public Object read() {
    if(canReadContinue) {
        incrementCount();
    } else {
        synchronized (writeLock) {
            System.out.println("Read thread has the lock.");
            canReadContinue = true;
            incrementCount();
        }
    }
    Object result = doRead();
    decrementCount();
    if(readCount == 0) {
        // TODO - release lock and notify

    }

    return result;
}

private synchronized void incrementCount() {
    readCount++;
}

private synchronized void decrementCount() {
    readCount--;
}


private void doWrite(Object newState) {
    // do stuff
}

private Object doRead() {
    return "";
}

}

Теперь мне нужен механизм для снятия блокировки в строке "// TODO - снять блокировку и уведомить", есть какие-нибудь указатели, как решить эту проблему?

Ответы [ 3 ]

5 голосов
/ 01 июля 2019

Советы:

  • Вам нужен мьютекс; например блокировка примитивного объекта.
  • Вам нужен счетчик количества читателей в настоящее время , удерживающий логическую блокировку чтения.
  • Вам нужен флаг, чтобы сказать, держит ли писатель логическую блокировку записи.
  • Вы удерживаете мьютекс, если и только вы приобретаете или освобождаете логическую блокировку. Получив его, вы отпускаете мьютекс.
  • Вам нужно будет использовать wait и notify.

Фактически вам необходимо 1 реализовать упрощенную версию ReadWriteLock.


1 - ... для выполнения домашнего задания. В реальной программе вы должны просто использовать существующий класс ReadWriteLock.

0 голосов
/ 02 июля 2019

Ответ на ваш обновленный код, вот какой скелет для вас:

public class SharedResource {

  private final Object signal = new Object();
  private boolean writeLocked;
  private int readerCount;

  public void write(final Object newState) throws InterruptedException {

    this.acquireWriteLock();

    try {

      // Now we know that no read and no other write is going on.
      System.out.println("Write thread has the lock.");
      this.doWrite(newState);

    } finally {
      // make sure we release the lock in any case.
      this.realeaseWriteLock();
    }

  }

  private void acquireWriteLock() throws InterruptedException {
    synchronized (this.signal) {

      // Wait until no more readers *and* no writer holds the lock.

      // To do: Insert the condition we need to wait for:

      while (/* condition here! */ ) {
        // To do: Wait for the lock-holding thread(s) to signal that they released their lock(s).
      }

      this.writeLocked = true; // Let others know that the write lock has been taken.

    }
  }

  private void realeaseWriteLock() {
    synchronized (this.signal) {

      this.writeLocked = false;

      // To do: Notify any and all other waiting threads that we released the lock!

    }
  }

  public Object read() {

    // To be done...

  }

  private void acquireReadLock() throws InterruptedException {
    synchronized (this.signal) {

      // Wait until no *writer* holds the lock.
      // To do: Insert condition we need to wait for:

      while (/* condition here! */ ) {
         // To do: Wait for the lock-holding thread(s) to signal that they released their lock(s).

      }

      // Now we know that no writer holds the lock. Acquire (another) read lock:

      this.readerCount++;

    }
  }

  private void releaseReadLock() throws InterruptedException {
    synchronized (this.signal) {

      this.readerCount--;

      // To do: Notify any threads waiting (i.e. writer threads).

      // (In fact only *required* if there are *no* more readers now because that's the only condition any thread will wait on.)

    }
  }

  private void doWrite(final Object newState) {
    // do stuff
  }

  private Object doRead() {
    return "";
  }

}

Главное, что нужно понять, может заключаться в том, что каждая попытка получить блокировку может потребовать wait, и что каждое снятие блокировки должно notify любых (потенциальных) ожидающих потоков.

0 голосов
/ 01 июля 2019

Далее я думаю использовать логический флаг, например, canReadContinue

Вы на правильном пути.Но помните, что любое число потоков может одновременно выполнять свои чтение доступы и что доступ на запись может быть выполнен только в том случае, если no другой поток в данный момент читает или пишет.

Таким образом, вам необходимо отслеживать, сколько читателей в настоящее время удерживают блокировку, и каждый читатель должен обязательно снять блокировку, когда она будет завершена.Только если & когда 0 читателей (и 0 писателей) удерживают блокировку, писатель может продолжить;и только если & когда 0 писателей удерживают блокировку, любой читатель может продолжить.

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