Java 优化读/写共享资源/内存位置,无需 Atomic API,例如 AtomicInteger

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

  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:


公共类共享资源{


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 - 释放锁并通知”行释放锁,任何指针如何解决这个问题?


哔哔one
浏览 103回答 3
3回答

萧十郎

提示:你需要一个互斥锁;例如原始对象锁。您需要一个当前持有逻辑读锁的读者数量的计数器。您需要一个标志来说明编写器是否持有逻辑写锁。当且仅当您正在获取或释放逻辑锁时,您才持有互斥锁。一旦获得它,就释放互斥量。您将需要使用wait和notify。实际上,您需要1实施简化版本ReadWriteLock。1 - ... 为了你的家庭作业。在真实世界的程序中,您应该简单地使用现有的ReadWriteLock类。

呼唤远方

在这里回答您更新的代码是您需要完成的一些框架: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任何(潜在的)等待线程。

倚天杖

此外,我正在考虑使用布尔标志,例如 canReadContinue你在正确的轨道上。但是请记住,任何数量的线程都可以同时执行它们的读取访问,并且只有在当前没有其他线程正在读取或写入的情况下才能进行写入访问。所以你需要跟踪当前有多少读者持有锁,并且每个读者都必须确保在完成后释放锁。只有当 0 个读者(和 0 个写者)持有锁时,一个写者才可以继续;并且仅当 & 当 0 个写入者持有锁时,任何读取者都可以继续。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java