-2

Why does InputStream's read method block the resource when there's nothing to read?

Let's say I've a RandomAccessFile opened in RW mode, and I create InputStream / OutputStream using File Descriptor.

Thread 1 is trying to read from the file, while nothing is available. At this time, if thread 2 tries to write to the file, it's blocked.

Why is that so?

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • 2
    Why don't you try it out for yourself and see? That's known as **research**, and is a great tool for developers to learn. – Andreas Mar 01 '19 at 01:16
  • I did that. Threads are blocked. I'm trying to understand why'd it block the whole resource ? –  Mar 01 '19 at 01:17
  • 1
    If you already know that it does block, why are you ask *if* it does? If you meant to ask *why*, how come your question is asking *"will it be blocked?"*, instead of *"why is it blocked?"*?? – Andreas Mar 01 '19 at 01:19
  • Updated. My bad. Please help me understand if you know. –  Mar 01 '19 at 01:22
  • 1
    The real question is, why you're creating InputStream / OutputStream from a File Descriptor, rather than creating them independently. – Andreas Mar 01 '19 at 01:23
  • I want to use an existing connection to the file, rather than creating a new one. –  Mar 01 '19 at 01:28
  • @NathanHughes台湾不在中国 Complete nonsense. Servlets and J2EE were envisaged from the start, and there is no non-blocking file I/O in NIO. – user207421 Mar 01 '19 at 02:10
  • Why aren't you using the `RandomAcessFile` directly to do the I/O? You'll find that is concurrent, where your bodge isn't. – user207421 Mar 01 '19 at 02:11
  • @user207421 How is RandomAccessFile concurrent? The kernel won't let two systems calls on the same RandomAccessFile execute concurrently. And secondly, even if it did, one RandomAccessFile has only one current file position, so you couldn't do anything useful with two threads at the same time in the same RandomAccessFile. – Erwin Bolwidt Mar 01 '19 at 04:20

1 Answers1

1

The FileDescriptor is the object carrying the OS file handle, which means it's the object carrying the file pointer.

Only one thread can use the file handle / file pointer at a time, because a FileDescriptor does not support multi-threading. Access has been synchronized.

If you want two threads to have independent access to the file, then you need two FileDescriptors.

To prove my point of shared file pointer, what do you think would happen if you alternately read from FileInputStream and write to FileOutputStream?

Here is code to show what happens:

String fileName = "Test.txt";
Files.writeString(Paths.get(fileName), "abcdefghijklmnopqrstuvwxyz", StandardCharsets.US_ASCII);

try (RandomAccessFile raFile = new RandomAccessFile(fileName, "rw");
     FileInputStream in = new FileInputStream(raFile.getFD());
     FileOutputStream out = new FileOutputStream(raFile.getFD()) ) {

    byte[] buf = new byte[4];
    for (int i = 0; i < 3; i++) {
        int len = in.read(buf);
        System.out.println(new String(buf, 0, len, StandardCharsets.US_ASCII));

        out.write("1234".getBytes(StandardCharsets.US_ASCII));
    }
}

String s = Files.readString(Paths.get(fileName), StandardCharsets.US_ASCII);
System.out.println(s);

Output

abcd
ijkl
qrst
abcd1234ijkl1234qrst1234yz

As you can see, reading 4 bytes returns bytes 0-3 and moves the file pointer, so writing of 4 bytes replaces bytes 4-7, then reading 4 bytes returns bytes 8-11, and writing of 4 bytes replaces bytes 12-15, and so forth.

Andreas
  • 154,647
  • 11
  • 152
  • 247