The current write-up doesn't actually say anything substantive on what gets handed to what, but I know what when I lecture on this I frequently suggest that the two client threads really only need their respective streams instead of the whole Socket. It turns out, though, that at least the Runnable that's handling standard input needs the whole Socket so it can call the Socket.shutdownOutput method when it's done receiving input from stdin.