一个OutputStream不断append文件,一个InputStream读同一个文件,读的速度比写快。当Reader 赶上Writer的时候会EOF,但不存在data corruption问题,不需要用户同步。
理论上也应该是这样:文件是按块存取的
1)如果读写不在一个块,挨不着,不存在问题
2)在一个块,变成了一个内存块的顺序读和顺序写的问题,OS会handle
内存块顺序读和顺序写的scenario,2个变量,head (next to read pointer), rear(next to put pointer)
读必须保证head < rear。
写操作有两个步骤:1)write item, 2)increment rear index,假设两个步骤之间线程被切换,读线程得到是旧的rear,只是在更远一格距离被停住
读操作的3个步骤:1)确认head 比rear小,2)进行读取,3)increment head index.
1)和2)之间切换,写线程只会增加rear,使得这个条件“更真”
2)和3)之间切换,head index压根不会被写线程修改,所以不存在同步问题。
写一个long 和读一个long都需要同步,因为可能读到写了一半的long,问题就在读指针逾越了写指针,写指针只写到一半,读指针可能读完。关键在于保证读指针不逾越写指针。
package queue;
import java.io.*;
public class Main {
public static void main(String[] args) {
try {
new Main().go();
} catch (Exception e) {
e.printStackTrace();
}
}
private void go() throws Exception
{
Thread t = new Thread( new Runnable () {
@Override
public void run() {
try {
OutputStream os = new FileOutputStream("c:\\queue.dat");
byte[] buff = new byte[4];
for (int i = 0; i < 10000; ++i) {
buff[0] = (byte)(i >> 24);
buff[1] = (byte)(i >> 16);
buff[2] = (byte)(i >> 8);
buff[3] = (byte) i;
os.write(buff, 0, buff.length);
System.out.println("Written " + i);
Thread.sleep(500);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
t.start();
Thread.sleep(3000);
InputStream is = new FileInputStream("c:\\queue.dat");
byte[] readBuff = new byte[4];
for (;;) {
if (is.read(readBuff, 0, readBuff.length) > 0) {
int x = 0;
x |= ((int)readBuff[0]) << 24;
x |= ((int)readBuff[1]) << 16;
x |= ((int)readBuff[2]) << 8;
x |= readBuff[3];
System.out.println("Read " + x);
Thread.sleep(250);
} else {
System.out.println("Queue empty, will wait a while.");
Thread.sleep(2000); //EOF reached, rest a while for producer to produce more
}
}
// System.out.println("Read Finished.");
}
}