Java optimized read/write a shared resource/memory location without Atomic API e.g. AtomicInteger

user10916892 :

There is a shared resource and we need to perform read/write operations on it as per below:

  1. When a write on resource is going on then no read should be allowed.
  2. When a read is going on then no write should be allowed but multiple read threads should be able to read.

I have written code like mentioned below but the problem with this code is all reads will be blocked when a single read thread has acquired the lock. Further i am thinking to use a boolean flag e.g. canReadContinue. Now the first time when read acquires a lock i will flip this flag to true and if it is true then other threads should not try to acquire the lock.

class SharedResource {

    Lock writeLock

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

    }

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

        doWrite(toBeWritten)

        writeLock.release()
    }

}

Expected is multiple threads should be able to read when no write is going on.

UPDATED 1 :

public class 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 "";
}

}

Now i need a mechanism to release the lock at line "// TODO - release lock and notify", any pointers how to resolve this issue ?

JimmyB :

Answering on your updated code here is some skeleton for you to complete:

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 "";
  }

}

The main point to understand may be that every attempt to take a lock may have to wait, and that every release of a lock should notify any (potential) waiting threads.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324756&siteId=1