JDK-6977788 : Write blocked while reading on a SocketChannel
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.nio
  • Affected Version: 6u20
  • Priority: P3
  • Status: Closed
  • Resolution: Duplicate
  • OS: generic
  • CPU: generic
  • Submitted: 2010-08-17
  • Updated: 2010-08-17
  • Resolved: 2010-08-17
Related Reports
Duplicate :  
Description
Although the documentation states that "Socket channels are safe for use by multiple concurrent threads. They support concurrent reading and writing, though at most one thread may be reading and at most one thread may be writing at any given time." Actually the writer gets blocked until the reader finishes.

$ java -version
java version "1.6.0_20"
Java(TM) SE Runtime Environment (build 1.6.0_20-b02)
Java HotSpot(TM) Server VM (build 16.3-b01, mixed mode)

My example application creates a SocketChannel against my localhost's echo service. Initially, to test everything works fine, the same thread writes a message to it and then read from it. This works correctly.

The main thread then creates a second thread and reads from the SocketChannel, as nothing is available it blocks. Once data is available for reading, the thread should unblock and read it.

The newly launched thread will first wait 5 seconds to guarantee that the other thread gets blocked while trying to read. After waiting it will try to write a message to the SocketChannel for the reader thread to read. However, it will get blocked and will be unable to write until the reader finishes.

The attached code produces the following output:

Thread Main - Sending message
Thread Main - Reading message
Thread Main - Correctly read the message
Thread Reader - Reading message
Sender Thread is delaying
(5 seconds delay)
Sender Thread is sending the message

At this point, the sender thread gets blocked while trying to write.

Comments
EVALUATION The output from jstack is this: 2010-08-17 18:01:42 Full thread dump Java HotSpot(TM) Server VM (16.3-b01 mixed mode): "Attach Listener" daemon prio=3 tid=0x0818f800 nid=0x10 waiting on condition [0x00000000] java.lang.Thread.State: RUNNABLE "Sender" prio=3 tid=0x08187c00 nid=0xf waiting for monitor entry [0xb641e000] java.lang.Thread.State: BLOCKED (on object monitor) at java.nio.channels.Channels.write(Channels.java:58) - waiting to lock <0xe5a523a8> (a java.lang.Object) at java.nio.channels.Channels.access$000(Channels.java:47) at java.nio.channels.Channels$1.write(Channels.java:134) - locked <0xe5a52be8> (a java.nio.channels.Channels$1) at java.io.OutputStream.write(OutputStream.java:58) at SenderThread.run(Main.java:90) "Low Memory Detector" daemon prio=3 tid=0x08161000 nid=0xd runnable [0x00000000] java.lang.Thread.State: RUNNABLE "CompilerThread1" daemon prio=3 tid=0x0815f000 nid=0xc waiting on condition [0x00000000] java.lang.Thread.State: RUNNABLE "CompilerThread0" daemon prio=3 tid=0x0815c400 nid=0xb waiting on condition [0x00000000] java.lang.Thread.State: RUNNABLE "Signal Dispatcher" daemon prio=3 tid=0x0815ac00 nid=0xa runnable [0x00000000] java.lang.Thread.State: RUNNABLE "Finalizer" daemon prio=3 tid=0x08148000 nid=0x9 in Object.wait() [0xb6713000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0xe5a00b10> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118) - locked <0xe5a00b10> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134) at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159) "Reference Handler" daemon prio=3 tid=0x08143400 nid=0x8 in Object.wait() [0xb6764000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0xe5a00a18> (a java.lang.ref.Reference$Lock) at java.lang.Object.wait(Object.java:485) at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116) - locked <0xe5a00a18> (a java.lang.ref.Reference$Lock) "main" prio=3 tid=0x08070000 nid=0x2 runnable [0xfe39e000] java.lang.Thread.State: RUNNABLE at sun.nio.ch.FileDispatcher.read0(Native Method) at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:21) at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:233) at sun.nio.ch.IOUtil.read(IOUtil.java:206) at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:236) - locked <0xe5a523b0> (a java.lang.Object) at sun.nio.ch.SocketAdaptor$SocketInputStream.read(SocketAdaptor.java:176) - locked <0xe5a523a8> (a java.lang.Object) at sun.nio.ch.ChannelInputStream.read(ChannelInputStream.java:86) - locked <0xe5a53140> (a sun.nio.ch.SocketAdaptor$SocketInputStream) at java.io.InputStream.read(InputStream.java:85) at Main.read(Main.java:59) at Main.main(Main.java:47) "VM Thread" prio=3 tid=0x08140800 nid=0x7 runnable "GC task thread#0 (ParallelGC)" prio=3 tid=0x08076c00 nid=0x3 runnable "GC task thread#1 (ParallelGC)" prio=3 tid=0x08078800 nid=0x4 runnable "GC task thread#2 (ParallelGC)" prio=3 tid=0x08079c00 nid=0x5 runnable "GC task thread#3 (ParallelGC)" prio=3 tid=0x0807b000 nid=0x6 runnable "VM Periodic Task Thread" prio=3 tid=0x08162c00 nid=0xe waiting on condition JNI global references: 685 In the stack we can see that the "sender" thread is waiting for lock <0xe5a523a8>, which is owned by the "main" (reader) thread.
17-08-2010