如何从使用另一个线程不断添加的文件中读取数据?

时间:2018-12-16 04:36:39

标签: java multithreading synchronized

我遇到一个问题“创建2个线程,一个将数据写入文件(从程序中定义的字符串),另一个将读取同一文件中的数据并将其显示在控制台上”。这是我的实现,但是陷入了无限循环

import java.io.* 
class ReaderWriter {
 int ch;
 FileInputStream fin;
 FileOutputStream fout;
 boolean rdrblocked = false;
 static volatile boolean running;
 static volatile boolean eof = false;
 String s = "This will end up in a file in the same order as it appears here or else we can conclude that there is some discrepancy related to some race condition stuff";
 byte b[] = s.getBytes();
 int length = b.length;

 void writer() throws Exception {
  fout = new FileOutputStream("Demo.txt");
  for (int i = 0; i < length; i++) {
   fout.write(b[i]);
   if (rdrblocked) {
    synchronized(this) {
     rdrblocked = false;
     notify();
    }
   }
  }
  eof = true;
  while (running) {
   synchronized(this) {
    rdrblocked = false;
    notify();
   }
  }
  fin.close();

 }

 void reader() throws Exception {
  running = true;
  fin = new FileInputStream("Demo.txt");
  if (fin.available() > 0) {
   while ((ch = fin.read()) != -1) {
    System.out.print((char) ch);
    while (fin.available() == 0 && !eof) {
     synchronized(this) {
      rdrblocked = true;
      wait();
     }
    }
   }
  }
  running = false;
  fin.close();
 }
}

class Writercall implements Runnable {
 Thread t;
 ReaderWriter obj;
 Writercall(ReaderWriter obj) {
  this.obj = obj;
  t = new Thread(this, "Reader");
  t.start();
 }
 public void run() {
  try {
   obj.writer();
  } catch (Exception e) {}
 }
}

class Readercall implements Runnable {
 Thread t;
 ReaderWriter obj;
 Readercall(ReaderWriter obj) {
  this.obj = obj;
  t = new Thread(this, "Writer");
  t.start();
 }
 public void run() {
  try {
   obj.reader();
  } catch (Exception e) {}
 }
}

class RWDemo {
 public static void main(String args[]) throws Exception {
  ReaderWriter obj1 = new ReaderWriter();
  Readercall r = new Readercall(obj1);
  Writercall w = new Writercall(obj1);
  try {
   r.t.join();
   w.t.join();
  } catch (Exception e) {}
 }
}

任何帮助和更好的实现方式将受到赞赏。 P.S:我使用了volatile以及isAAlive(),但它不起作用,我认为问题是在writer的while循环中,读取器将布尔变量更新为false并没有反映在读取器中。 P.P.S:是的,我知道这是实现并发的低效率方法,但是我很好奇这是否可行。 编辑:我已经按照muradm的建议更新了代码。仍然欢迎对代码进行任何改进。(更新的代码链接在上面)

1 个答案:

答案 0 :(得分:0)

问题是您试图立即打开同一文件。只是给您一个想法:

// omitted
void reader() throws Exception {
    // reader waits before writer notify
    // writer notifies reader to wake up
    synchronized (this) {
        rdrblocked = true;
        wait();
    }
    while (!new File("Demo.txt").exists() && running) {
        Thread.sleep(10);
    }
    fin = new FileInputStream("Demo.txt");
    if (fin.available() > 0) {
        while ((ch = fin.read()) != -1) {
            System.out.print((char) ch);
        }
    }
    // omitted

即由于文件开头不存在,因此读写器可能会从OS获取不同的句柄。让读者检查文件是否存在并等待其存在将解决问题,但是仍然...

但是,这似乎不是一个好的解决方案。您的目的尚不清楚:

  • 您要连续读写文件,还是一次操作?如果连续不断,则必须牢记EOF,一旦读者到达EOF,您的句柄就应该无效,尽管作者可能在读者的RandomAccessFile事件之后继续写入文件。
  • 您为什么要在单一过程的范围内做这种事情?

如果背后有实际任务,您将需要寻找更复杂的解决方案以实现对单个文件的可靠读取/写入。像wait()一样。

此外,如果您正在计算notify()wait(),那么notify()应该在wait()之前出现,否则,如果您在数据之后notified()从文件中读取,然后实际上是写者wait(),甚至连读者都开始读wait()。即服务员会错过在value呼叫之前发生的通知。