in what way is java.net.Socket threadsafe?

14,197

Solution 1

You actually read from InputStream and write to OutputStream. They are fairly independent and for as long as you serialize access to each of them you are ok.

You have to correlate, however, the data that you send with data that you receive. That's different from thread safety.

Solution 2

Sockets are thread unsafe at the stream level. You have to provide synchronization. The only warranty is that you won't get copies of the exact same bytes in different read invocations no matter concurrency.

But at a Reader and, specially, Writer level, you might have some locking problems.

Anyway, you can handle read and write operations with the Socket's streams as if they were completely independent objects (they are, the only thing they share is their lifecyle).

Once you have provided correct synchronization among reader threads on one hand, and writer threads on the other hand, any number of readers and writers will be okay. This means that, yes, you can read on one thread and write on another (in fact that's very frequent), and you don't have to stop reading while writing.

One last advice: all of the operations involving threads have associated timeout, make sure that you handle the timeouts correctly.

Solution 3

Java java.net.Socket is not actually thread safe: Open the Socket source, and look at the (let say) connected member field and how it is used. You will see that is not volatile, read and updated without synchrinization. This indicates that Socket class is not designed to be used by multiple threads. Though, there is some locks and synchronization there, it is not consistent.`

I recommend not to do it. Eventually, use buffers(nio), and do socket reads/writes in one thread

For details go the the discussionv

Solution 4

You can have one thread reading the socket and another thread writing to it. You may want to have a number of threads write to the socket, in which case you have to serialize your access with synchronization or you could have a single writing thread which gets the data to write from a queue. (I prefer the former)

You can use non-blocking IO and share the reading and writing work in a single thread. However this is actually more complex and tricky to get right. If you want to do this I suggest you use a library to help you such as Netty or Mina.

Share:
14,197
lacker
Author by

lacker

Updated on July 19, 2022

Comments

  • lacker
    lacker almost 2 years

    I have a Socket that I am both reading and writing to, via BufferedReaders and BufferedWriters. I'm not sure which operations are okay to do from separate threads. I would guess that writing to the socket from two different threads at the same time is a bad idea. Same with reading off the socket from two different threads at the same time. What about reading on one thread while writing on another?

    I ask because I want to have one thread blocked for a long time on a read as it waits for more data, but during this wait I also have occasional data to send on the socket. I'm not clear if this is threadsafe, or if I should cancel the read before I write (which would be annoying).

  • dhblah
    dhblah almost 13 years
    What do you mean as "serialize access to each of them"?
  • Paŭlo Ebermann
    Paŭlo Ebermann almost 13 years
    @gasan: don't try to write with two threads at once, or read with two threads at once. Call the reads/writes from some synchronized block/method (one lock for read, one for write).
  • Op De Cirkel
    Op De Cirkel almost 13 years
    Even getInputStream() is not thread save, as it does isConnected() in a not thread-safe fashion. This is enough not to use it by multiple threads at all if you do not provide synchronization.
  • Op De Cirkel
    Op De Cirkel almost 13 years
    >>> as long as you serialize access to each of them: That is not enough to make the access thread-safe, you have to make sure that the Socket state is managed using the same lock that is used to serialize the access. I recommend, simply don't do it. Use buffers, and manage socket reads/writes in one thread
  • user207421
    user207421 almost 13 years
    There's an awful lot of code out there that would break if this was even remotely true. The 'connected' member is only set once in the life of the socket. The basic issue is that the input stream is separate from the output stream and the underlying TCP stream is full duplex: there is no thread-unsafety there.
  • Op De Cirkel
    Op De Cirkel almost 13 years
    @EJP it is not only connected, another one is created. Do you want to have random behavior because the SocketImpl is not properly initialized when trying to use it?
  • Op De Cirkel
    Op De Cirkel almost 13 years
    I don't think that there is a lot of code that accesses single open Socket from different threads. That is because, usually, you have a protocol and you write based on what you've read before and other way around. Doing this in different threads (IMO) is very unusual
  • Op De Cirkel
    Op De Cirkel almost 13 years
    >>> the input stream is separate from the output stream If those are different objects, doesn't mean that they do not access the same state of the socket. Browse a little bit the sources of Socket, SocketImpl, PlainSocketImpl, etc and you will see that the streams actually have state in common. The class not being designed for multi-threading (give me java-doc/spec that says it is safe) is reason enough not to do it
  • Op De Cirkel
    Op De Cirkel almost 13 years
    >>> There's an awful lot of code Give me an example of some FOSS project that is doing that.
  • user207421
    user207421 almost 13 years
    Your questions are futile. Obviously nobody wants random behaviour. The question is whether there will really be any random behaviour. I've never seen any, in 14 years. As I said, there is an awful lot of code that would break if your contention was correct. RMI/Jeri in Jini is a very prominent example of code that reads and writes in separate threads.
  • Op De Cirkel
    Op De Cirkel almost 13 years
    >>> TCP stream is full duplex: This means that there are separate byte streams for in and out, but does not mean that you can use the socket library (java, libc, etc) in concurrent fashion.
  • user207421
    user207421 almost 13 years
    Oh come off it. There is no socket support whatsover in libc so that is completely irrelevant. We are discussing the Java API in java.net. What are all the acquireFD()/releaseFD() calls for it if it isn't intended to be used by multiple threads?
  • Op De Cirkel
    Op De Cirkel almost 13 years
    >>> There is no socket support whatsover in libc gnu.org/s/hello/manual/libc/index.html#toc_Sockets
  • user207421
    user207421 almost 13 years
    The glibc example uses system calls only: socket(), bind(), connect(), etc, and they are all threadsafe. There is no library to speak of, other than the DNS functions.
  • Op De Cirkel
    Op De Cirkel almost 13 years
    >> I've never seen any, in 14 years I am not talking about what you've seen, i am talking about what is written in the java.net.Socket & friends
  • user207421
    user207421 almost 13 years
    'I don't think that there is a lot of code': We are not talking about what you think either, we are talking about facts. You haven't answered my question about acquiring and releasing FDs and you haven't addressed my very conspicuous counter-example to what you 'don't think'.
  • Op De Cirkel
    Op De Cirkel almost 13 years
    >>> acquiring and releasing FDs FDs are part of the implementation of PlainSocketImpl and are used only to transfer control to the native code. .... And even the FDs are accessed in inconsistent way as they are not volatile, neither access to them is always synchronized
  • Op De Cirkel
    Op De Cirkel almost 13 years
  • user207421
    user207421 about 12 years
    Re the 'discussion' you've now linked to, there is no 'discussion', there, it is just a copy of all these comments up to but excluding this point. You still haven't addressed my point about all the zillions of lines of code, starting with Java RMI itself, that would fail if there was any synchronization issue with Sockets. Let's be realistic. Regardless of the state of the Javadoc etc there is absolutely zero possibility of things being changed so that RMI breaks.
  • beroal
    beroal over 4 years
    @user207421 Actually, there is an indication in the Java documentation that a socket may be accessed from different threads: “close - Any thread currently blocked in an I/O operation upon this socket will throw a SocketException.”