2011-05-22 74 views
2

这是读者作者的实现,即许多读者可以读取,但只有一个作者可以在任何时候写入。这是否按预期工作?读者作者并发问题Java

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() 

例如任何不同?

感谢

+0

在我看来,你应该避免等待/通知一个公共对象,因为this.class或这是。这允许roque代码搞砸你的同步。同步对象应该是此类的专用字段。 – MeBigFatGuy 2011-05-22 18:39:34

+0

这功课吗?如果没有@亚历克斯吉特曼的答案可能会被接受。 – 2011-05-22 19:07:53

+0

>这是否按预期工作? (a)你期望什么? (b)它有什么作用? (c)有区别吗? – EJP 2011-05-23 02:21:44

回答

6

没有 - 你含蓄调用this.wait(),尽管没有上this同步,而是在类。同样,您在read_end中致电this.notifyAll()。我的建议:

  • 不要延长Thread - 你不是专业的线程都没有。
  • 不要在实例成员中使用类似这样的静态变量;它使它看起来像就像有每个对象的状态,但实际上没有。就个人而言,我只是使用实例变量。
  • 不要使用下划线的名字 - 常规的Java名称将numReadersreadEnd(或更好,endRead)等
  • 请在任this同步或类,如果你能帮助它。我个人更喜欢有一个private final Object变量锁定(并等待)。这样你就知道只有你的代码可以在它上面进行同步,这样就更容易推理了。
  • 您从未将writing设置为0.首先使用整数而不是boolean的任何原因?

当然,如果可能的话最好在框架中使用类,但是我希望你真的写这个更好地理解线程。

+0

@Ferguzz:不 - 你仍然没有将'write'设置为0(在'write_end'中),并且无论它们的实例如何(完成类),仍然会令* instance *方法完全混淆。查看我要修复的项目符号列表。 – 2011-05-22 18:44:47

2

read_start的具体实现不等于简单地声明方法​​。正如J. Skeed所指出的那样,您需要拨打notify(和wait)上的对象synchronize。你不能使用一个不相关的对象(在这里:类)。并且使用在方法上修改的​​不会使该方法隐式调用wait或类似的东西。

有,顺便说一句,读/写锁的实现,随核心JDK提供:java.util.concurrent.locks.ReentrantReadWriteLock。使用一个,你的代码可能看起来像,而不是执行以下操作:

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

使用

final Resource r = ...; 

r.readLock().lock(); 
try { 
    r.read(); 
} finally { 
    r.unlock(); 
} 

,并在写操作类似。

3

您可以通过使用

java.util.concurrent.locks.ReentrantReadWriteLock 

只要抓住java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock中,当你开始阅读和java.util.concurrent.locks.ReentrantReadWriteLock中实现自己的目标,更简单的方式。 WriteLock当你开始写作时。

该课程正是为此而准备的 - 允许多个阅读器与单个作者互斥。

0

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

+0

这是所需的行为。任何一个线程都可以自行写入。或者当没有线程正在写入时,许多线程可以读取。 – Ferguzz 2011-05-22 19:01:07