并发Java中的读写器问题

并发Java中的读写器问题,java,concurrency,readerwriterlock,Java,Concurrency,Readerwriterlock,这是readers-writer的一个实现,即许多读者可以阅读,但在任何时候只有一个作者可以写作。这是否如预期的那样有效 public class ReadersWriters extends Thread{ static int num_readers = 0; static int writing = 0; public void read_start() throws InterruptedException { synchronized(this.getC

这是readers-writer的一个实现,即许多读者可以阅读,但在任何时候只有一个作者可以写作。这是否如预期的那样有效

public class ReadersWriters extends Thread{

static int num_readers = 0;
static int writing = 0;

public void read_start() throws InterruptedException {         

    synchronized(this.getClass()) {
        while(writing == 1) wait();
        num_readers++;
    }        
}

public void read_end() {
    synchronized(this.getClass()) {
        if(--num_readers == 0) notifyAll();
    }
}

public void write_start() throws InterruptedException{

    synchronized(this.getClass()) {
        while(num_readers > 0) wait();
        writing = 1;
    } 
}

public void write_end() {
    this.getClass().notifyAll();
}
}
这个实现与声明每个方法有什么不同吗

public static synchronized read_start() 
比如说


谢谢

否-您正在隐式调用
this.wait()
,尽管没有在
this
上进行同步,而是在类上进行同步。同样,您正在
read\u end
中调用
this.notifyAll()
。我的建议是:

  • 不要扩展
    线程
    -您根本没有专门化线程
  • 不要从实例成员中使用这样的静态变量;它使每个对象看起来都有状态,但实际上没有。我个人只会使用实例变量
  • 不要在名称中使用下划线-传统的Java名称应该是
    numReaders
    readEnd
    (或者更好,
    endRead
    )等等
  • 如果可以,请不要在
    或类上同步。就个人而言,我更喜欢使用
    私有final对象
    变量来锁定(并等待)。这样,您就知道只有您的代码可以在其上同步,从而更容易进行推理
  • 您从未将
    写入设置为0。首先使用整数而不是布尔值的原因是什么

当然,如果可能的话,最好使用框架中的类来实现这一点,但我希望您编写这篇文章是为了更好地理解线程。

您对
read\u start
的特定实现并不等同于简单地声明方法
synchronized
。正如J.Skeed所指出的,您需要对要与之同步的对象调用
notify
(和
wait
)。不能为此使用不相关的对象(此处为类)。在一个方法上使用
synchronized
modified不会使该方法隐式调用
wait
或类似的东西

顺便说一句,有一个读/写锁的实现,它与核心JDK一起提供。使用该选项,您的代码可能会如下所示:

class Resource {
    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    private final Lock rlock = lock.readLock();
    private final Lock wlock = lock.writeLock();

    void read() { ... /* caller has to hold the read lock */ ... }
    void write() { ... /* caller has to hold the write lock */ ... }

    Lock readLock() { return rlock; }
    Lock writeLock() { return wlock; }
}
用法


写操作也是如此。

通过使用

java.util.concurrent.locks.ReentrantReadWriteLock
开始阅读时只需抓取java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock,开始写作时抓取java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock


该类正是为了实现这一点-允许多个读卡器与单个编写器互斥。

示例代码在
This.getClass()
上同步,这将为同一类加载器中的多个
读卡器
实例返回相同的
对象。如果存在多个
ReadersWriters
实例,即使您有多个线程,也会存在对此共享锁的争用。这类似于将
static
关键字添加到私有锁字段(正如Jon Skeet所建议的),并且可能会导致比在
或私有锁对象上同步性能更差的性能。更具体地说,一个正在读取的线程将阻塞另一个正在写入的线程,这可能是不可取的。

在我看来,您应该避免等待/通知一个公开可用的对象,例如this.class或this。这允许roque代码破坏同步。同步对象应该是此类的私有字段。这是作业吗?如果没有,那么@Alex Gitelman的答案很可能会被接受。>这是否如预期的那样有效?(a) 你期待什么?(b) 它有什么作用?(c) 有什么不同吗?@Ferguzz:No-您仍然没有将
write
设置为0(在
write_end
中),并且完全不考虑实例而创建实例方法(而不是获取类)仍然令人困惑。请参阅我要修复的要点列表。这是必需的行为。任何一个线程都可以自己写。或者,当没有线程写入时,许多线程可以读取。
java.util.concurrent.locks.ReentrantReadWriteLock