Reader java 中的编写器实现
Reader Writer implementation in java
我正在尝试使用通知和等待实现一个 reader-writer。但我想我被困住了。
我的顺序是这样的。
RRRRRRRRRRWWWWWWWWW
如果主程序以 reader 首先调用,就会发生这种情况。
要么
WWWWWWWRRRRRRRRRRR
。如果主程序首先调用编写器,就会发生这种情况。
看起来读取通知根本不起作用。编写器线程永远不会执行。
如果我在 运行 方法中使 while 循环变为 运行 无限那么它只是
RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR........
。作家没有机会写作。
你能看看这个吗?
数据CLASS
public class Data {
private int q ;
private boolean isAnyOneReading;
public Data() {
}
public void readQ() {
synchronized (this){
isAnyOneReading = true;
System.out.println("Read start "+q);
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (this){
isAnyOneReading = false;
System.out.println("Read end "+q);
notifyAll();
}
}
public synchronized void writeQ(int q) {
System.out.println(isAnyOneReading);
while (isAnyOneReading){
try{
wait();
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("Done");
Thread.currentThread().interrupt();
}
}
System.out.println("Write start "+q);
this.q = q;
try{
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
System.out.println("Write end "+q);
notifyAll();
}
}
READER CLASS
public class Reader implements Runnable {
private Data data;
private Thread readerThread;
public Reader(Data data) {
this.data = data;
readerThread = new Thread(this, "ReaderThread");
}
void startThread(){
readerThread.start();
}
@Override
public void run() {
int i = 0 ;
while (i != 5){
data.readQ();
i++;
}
}
}
作者CLASS
public class Writer implements Runnable{
private Data data;
private Thread writerThread;
public Writer(Data data) {
this.data = data;
writerThread = new Thread(this,"WriterThread," );
}
void startThread(){
writerThread.start();
}
@Override
public void run() {
int i = 0 ;
int j = 0 ;
while (j != 5){
data.writeQ(i++);
// i++;
j++;
}
}
}
主要CLASS
public class ReaderWriterDemo {
public static void main(String[] args) {
Data data = new Data();
Reader reader = new Reader(data);
Writer writer = new Writer(data);
reader.startThread();
writer.startThread();
}
}
尝试从数据 class 中删除 Thread.sleep。
并像这样在 运行 方法中添加 Thread.sleep 。 (粘贴一个示例):
@Override
public void run() {
int i = 0;
while (i != 5) {
data.readQ();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
i++;
}
}
}
Read 的 notifyAll() 有效,但似乎 read() 再次被调用并在 write() 中的任何其他操作之前更改 isAnyOneReading 的值。这就是检查失败并且 write() 再次开始等待的原因。正如 Danny Fried 建议的那样,将 Thread.sleep() 移动到 运行 方法会有所帮助。
看起来像一个简单的饥饿案例。考虑您的作者的主循环:
while (j != 5){
data.writeQ(i++);
// i++;
j++;
}
data.writeQ()
是一个 synchronized
方法:它在 returns 之前做的最后一件事是解锁锁。它在下一次调用时做的第一件事就是重新锁定锁。中间没有发生太多事情——递增和测试一个局部变量就够了。
Java synchronized
锁不 公平 。 (即,当锁可用时,系统 而不是 保证获胜者将是等待时间最长的线程。)事实上,它可能是 相反的公平:OS可能会尝试通过始终选择最容易唤醒的线程来最大化CPU(s)的有效使用。
当作者在每次后续迭代中返回调用 data.writeQ()
时,可能 OS 甚至还没有 started 唤醒reader,它只是让作者再次输入 synchronized
块。
您的 reader 也会发生同样的事情。代码有点复杂,但就像在 writer 中一样,data.readQ()
在返回之前做的最后一件事是解锁锁,而在下一次调用时它做的第一件事就是锁定它再次.
暴力破解:用fair ReentrantLock
object.
替换synchronized
块
替代解决方案,这对于实际运行的程序而言更为典型:让线程在两者之间做 其他事情(例如,让它们做一些 I/O)调用锁定的函数,从而让其他线程有机会进入并使用锁定的资源。
我正在尝试使用通知和等待实现一个 reader-writer。但我想我被困住了。
我的顺序是这样的。
RRRRRRRRRRWWWWWWWWW
如果主程序以 reader 首先调用,就会发生这种情况。
要么
WWWWWWWRRRRRRRRRRR
。如果主程序首先调用编写器,就会发生这种情况。
看起来读取通知根本不起作用。编写器线程永远不会执行。
如果我在 运行 方法中使 while 循环变为 运行 无限那么它只是
RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR........
。作家没有机会写作。
你能看看这个吗?
数据CLASS
public class Data {
private int q ;
private boolean isAnyOneReading;
public Data() {
}
public void readQ() {
synchronized (this){
isAnyOneReading = true;
System.out.println("Read start "+q);
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (this){
isAnyOneReading = false;
System.out.println("Read end "+q);
notifyAll();
}
}
public synchronized void writeQ(int q) {
System.out.println(isAnyOneReading);
while (isAnyOneReading){
try{
wait();
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("Done");
Thread.currentThread().interrupt();
}
}
System.out.println("Write start "+q);
this.q = q;
try{
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
System.out.println("Write end "+q);
notifyAll();
}
}
READER CLASS
public class Reader implements Runnable {
private Data data;
private Thread readerThread;
public Reader(Data data) {
this.data = data;
readerThread = new Thread(this, "ReaderThread");
}
void startThread(){
readerThread.start();
}
@Override
public void run() {
int i = 0 ;
while (i != 5){
data.readQ();
i++;
}
}
}
作者CLASS
public class Writer implements Runnable{
private Data data;
private Thread writerThread;
public Writer(Data data) {
this.data = data;
writerThread = new Thread(this,"WriterThread," );
}
void startThread(){
writerThread.start();
}
@Override
public void run() {
int i = 0 ;
int j = 0 ;
while (j != 5){
data.writeQ(i++);
// i++;
j++;
}
}
}
主要CLASS
public class ReaderWriterDemo {
public static void main(String[] args) {
Data data = new Data();
Reader reader = new Reader(data);
Writer writer = new Writer(data);
reader.startThread();
writer.startThread();
}
}
尝试从数据 class 中删除 Thread.sleep。 并像这样在 运行 方法中添加 Thread.sleep 。 (粘贴一个示例):
@Override
public void run() {
int i = 0;
while (i != 5) {
data.readQ();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
i++;
}
}
}
Read 的 notifyAll() 有效,但似乎 read() 再次被调用并在 write() 中的任何其他操作之前更改 isAnyOneReading 的值。这就是检查失败并且 write() 再次开始等待的原因。正如 Danny Fried 建议的那样,将 Thread.sleep() 移动到 运行 方法会有所帮助。
看起来像一个简单的饥饿案例。考虑您的作者的主循环:
while (j != 5){
data.writeQ(i++);
// i++;
j++;
}
data.writeQ()
是一个 synchronized
方法:它在 returns 之前做的最后一件事是解锁锁。它在下一次调用时做的第一件事就是重新锁定锁。中间没有发生太多事情——递增和测试一个局部变量就够了。
Java synchronized
锁不 公平 。 (即,当锁可用时,系统 而不是 保证获胜者将是等待时间最长的线程。)事实上,它可能是 相反的公平:OS可能会尝试通过始终选择最容易唤醒的线程来最大化CPU(s)的有效使用。
当作者在每次后续迭代中返回调用 data.writeQ()
时,可能 OS 甚至还没有 started 唤醒reader,它只是让作者再次输入 synchronized
块。
您的 reader 也会发生同样的事情。代码有点复杂,但就像在 writer 中一样,data.readQ()
在返回之前做的最后一件事是解锁锁,而在下一次调用时它做的第一件事就是锁定它再次.
暴力破解:用fair ReentrantLock
object.
synchronized
块
替代解决方案,这对于实际运行的程序而言更为典型:让线程在两者之间做 其他事情(例如,让它们做一些 I/O)调用锁定的函数,从而让其他线程有机会进入并使用锁定的资源。