Java优化的读/写共享资源/内存位置而无需Atomic API,例如原子整数

时间:2019-07-01 13:02:35

标签: java multithreading concurrency

有一个共享资源,我们需要按照以下说明对其执行读/写操作:

  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 个答案:

答案 0 :(得分:5)

提示:

  • 您需要互斥锁;例如原始对象锁。
  • 您需要一个计数器,该计数器当前拥有逻辑读取锁的读取器的数量。
  • 您需要一个标志来说明写者是否持有逻辑写锁。
  • 仅当您正在获取或释放逻辑锁时,您才持有互斥量。一旦获得它,就释放互斥锁。
  • 您将需要使用waitnotify

有效地,您需要 1 实施简化版本ReadWriteLock


1-...用于作业分配。在现实世界的程序中,您应该简单地使用现有的ReadWriteLock类。

答案 1 :(得分:0)

  

我还想使用布尔标志,例如canReadContinue

您在正确的轨道上。但是请记住,任何数量的线程都可以同时执行其 read 访问,并且只有在当前正在读取 no 的其他线程时才能进行写访问。或写作。

因此,您需要跟踪当前有多少个读取器持有该锁,并且每个读取器必须确保完成后释放该锁。仅当&当0个读者(和0个作者)持有锁时,作者才可以继续操作;并且只有当&当0个作者持有锁时,任何读者才可以继续。

答案 2 :(得分:0)

在此处更新代码的答案是您需要完成的一些工作:

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任何(潜在)等待线程。