【问题标题】:How to read and write data into same file simultaneously如何同时读取和写入数据到同一个文件
【发布时间】:2012-12-26 18:59:45
【问题描述】:

我已经阅读了很多帖子,其中谈到了使用 JavaME 同时读取和写入文件。我有一个特殊的用例场景,其中我的日志文件(可能是完整文件或只是文件的一部分)定期上传到服务器。这必须在不妨碍应用程序在同一文件中的当前日志记录的情况下继续进行。

代码示例如下:

boolean writing = true;
boolean reading = true;
void main() {
    new Thread("THREAD-FILE-READ") {
        public void run() {
            InputStream instream = getFileInStream();
            if (null != instream) {
                while (reading) {
                    try {
                        try {
                            synchronized(READ_LOCK) {
                                READ_LOCK.wait();
                            }
                        } catch (InterruptedException ex) {
                            ex.printStackTrace();
                        }

                        if (writtenCharsLen > 0) {
                            byte[] bytes = new byte[writtenCharsLen];
                            instream.read(bytes, 0, writtenCharsLen);
                            System.out.println("Read="+new String(bytes));
                            bytes = null;
                            writtenCharsLen = 0;
                        }
                    } catch (IOException ioe) {
                        ioe.printStackTrace();
                    }
                }
            }
            closeStream(instream);
        }
    }.start();

    new Thread("THREAD-FILE-WRITE") {
        public void run() {
            OutputStream outstream = getFileOutStream();
            if (null != outstream) {
                while (writing) {
                    try {
                        byte[] str = randomString();
                        if (null != str) {
                            writtenCharsLen = str.length;
                            System.out.println("Write=" + new String(str));
                            outstream.write(str);
                            str = null;
                        }
                    } catch (IOException ex) {
                        ex.printStackTrace();

                    } finally {
                        notifyReadStream();
                    }

                    try {
                        synchronized(WRITE_LOCK) {
                            WRITE_LOCK.wait();
                        }
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                }
            }
            closeStream(outstream );
        }
    }.start();

}

void notifyReadStream() {
    try {
        synchronized (READ_LOCK) {
            READ_LOCK.notify();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

void notifyWriteStream() {
    try {
        synchronized (WRITE_LOCK) {
            WRITE_LOCK.notify();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

在上面的代码中,我将用对网络 IO 方法的正确调用来替换 sop-read 和 sop-write。

PS:由于这段代码将运行多个文件和多个设备,我需要尽可能压缩修改以保持我的运行时堆尽可能低。此外,这段代码将一直运行到应用程序生命周期,因此不考虑在中间关闭和打开文件。

出现不希望的结果: 读写线程显示正在运行的读写操作。读取线程正在从写入线程已写入的位置读取。我在这段代码中没有遇到任何异常,但结果是不希望的。我也尝试过同步读写流,但那是抛出IllegalMonitorStateException

预期结果: 流的读取必须在写入流完成后触发,并且读取线程必须能够从文件中的任何位置读取。

任何帮助/指针有用吗?

编辑:我能够使用不同的监视器同步读取和写入流,但我仍然觉得,我可以使用单个监视器做得更好。稍后会尝试。

【问题讨论】:

  • 您对多线程代码的适应程度如何?例如,Jenkov's tutorial 中的主题看起来很熟悉吗?鉴于 J2ME 的限制,我会说这是我见过的最相关的介绍
  • @gnat,感谢您的链接,阅读它真的很有见地。是的,我对多线程移动环境和开发非常满意。请检查我的问题描述,我已经编辑了同步实现。我现在正在研究的下一个问题是如何巧妙地,以及使用多个变量来记录添加/删除的字节数的传统方式,从我拥有的最后一个位置的文件中读取足够的字节已经上传到服务器了。我正在为这个实现寻找一种优化的方法。
  • 对于那个下一个问题,你考虑过BlockingQueue吗? Jenkov 的章节中有解释和代码。如果我理解正确,“THREAD-FILE-WRITE”将enqueue 和“THREAD-FILE-READ”将dequeue
  • @gnat,是的,我有。正如你所说,它将入队和出队,我可以通过对我的监视器进行排序来实现。我现在的直接问题是如何有效地从写入器写入的文件中读取足够的字节以发送到服务器。我知道我可以通过使用存储文件中字节的当前位置和新位置的变量来做到这一点,但我的目标是优化方法 bcoz (a) 它的 IO 操作是资源密集型的 & (b) 这将发生为多次通知读取队列。我正在考虑一些更简单的方法来解决上述问题。
  • 我明白了。看起来你正在寻找一些有趣的东西。 :) 就队列而言,您必须设计什么、何时以及如何入队/出队,对吗?

标签: java multithreading java-me midp


【解决方案1】:

我将解决这个问题:

Present Undesired Result:读写线程显示正在运行的读写操作。读取线程正在从写入线程已写入的位置读取。我在这段代码中没有遇到任何异常,但结果是不希望的。我也尝试过同步读写流,但那是抛出IllegalMonitorStateException

如果您已使用监视器同步访问,即读取器调用someObject.wait() 而写入器调用someObject.notify(),请记住您必须将这些调用包装在someObject 上的同步块中:

synchronized(someObject) {
    someObject.wait();
}


synchronized(someObject) {
    someObject.notify();
}

这就是IllegalMonitorStateException的原因。

【讨论】:

  • 感谢您的回复!使用这种方法,我不能在这些线程中等待同一个监视器。是的,我已经同步了我的监视器,这就是它抛出IllegalMonitorStateException 的原因,因为我需要等到写线程上的下一次写入并等到读线程中的下一次读取。现在我正在努力为每个线程设置单独的监视器,让大家保持最新状态。
  • @Vimal:您必须在调用等待/通知的完全相同的对象上进行同步。但是为什么你不能在两个线程的同一个监视器上等待/通知呢?
  • 如果我在这些线程中使用与monitor.notify() 相同的监视器,它会通知两个线程并且再次读取和写入是异步的。
  • @Vimal 但我以为你只想让读者等到写作完成?
  • 如果作者不等待,那么它将无休止地继续将数据写入输出文件。所以需要它只在新日志可用时才写入文件。一旦写入器将数据写入文件,读取器必须立即读取它并将其发送到服务器。因此,OP。
【解决方案2】:

您的第一个问题是您在写入数据之前设置了writtenCharsLen。如果您的读取线程在写入线程实际写入它之前看到它是非零的,那么您就有问题了。写入后移动writtenCharsLen = str.length。

我在您的示例中看到的另一个问题是线程永远不会产生控制权。他们会占用 CPU。

【讨论】:

  • 感谢您的意见!但是在写入流之后移动 writeCharsLen... 并没有解决 OP,因为它仍然是从流中异步读取。接下来,线程不能让步,因为它是从文件读取/写入文件的持续过程,最终将与服务器交互以上传数据。
猜你喜欢
  • 2011-01-30
  • 2019-03-04
  • 1970-01-01
  • 2018-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-09
相关资源
最近更新 更多