2

I am writing a multi-thread program in Java, where i am creating a seperate thread to handle each new client connection. I have:

Socket s;


while(true)
{
    s = server.accept();
    ClientHandler ch = new ClientHandler(s);
    Thread servingThread = new Thread(ch);
    servingThread.start();
}

In the ClientHandler thread i have:

public class ClientHandler implements Runnable
{
    private Socket s;

public ClientHandler(Socket _Socket, boolean _accepted, BaseStation _bs)
{
    this.s = _Socket;
}

If in Java i can't pass an object but only a reference to it, isn't that going to cause a problem, to the s instance inside ClientHandler whenever server accepts a new connection? Is it not going to change inside ClientHandler too and corrupt it? If so, what's the correct way to do it?

nikos
  • 2,893
  • 11
  • 30
  • 39

3 Answers3

2

See Is Java "pass-by-reference" or "pass-by-value"? to explain.

Passing a new Socket instance to a new ClientHandler instance is fine because each ClientHandler has its own Socket - changes to the value of the local variable s do not impact copy of the Socket instance inside ClientHandler.

Something like this would cause a problem:

ClientHandler ch = new ClientHandler(s);
Thread servingThread = new Thread(ch);
servingThread.start();

s.someMethod(); // close, read etc.

Because ch.s and s both point to the same underlying Socket object instance.

BTW: spinning off a whole new Thread in a while loop is probably bad unless you're sure those threads will terminate. Probably better to use a ThreadPool.

Community
  • 1
  • 1
wrschneider
  • 17,913
  • 16
  • 96
  • 176
2

Your concern is correct because the Socket object (like any other object in Java) is passed by reference, therefore there is a probability of it being referenced by different modules, or different threads, causing unpredictable behaviour.

However in case of your program there is no problem. The reason is: whenever server accepts a new connection it will create a new Socket object, which you are then passing to a new instance of ClientHandler. Therefore every new connection from the client will be served by an independent ClientHandler instance, so there are no race conditions to the Socket object to worry about. So you are safe for now.

As a counter-example if you decide to create two ClientHandler threads to read from the same Socket object like this ...

s = server.accept();
ClientHandler ch = new ClientHandler(s);
ClientHandler ch2 = new ClientHandler(s);
new Thread(ch).start();
new Thread(ch2).start();

... then you might be in trouble because two ClientHandlers will get the same reference to the same Socket object and if both attempt to read from the same socket they will each get only half of the data. E.g. if you are receiving a string "hello", you might end up with ch reading "hel" and ch2 reading "lo", or any other combination.

rodion
  • 14,729
  • 3
  • 53
  • 55
1

It's a bit confusing, but your code should work as shown. Java first passes by value, and then by reference. I.E., you're not passing in a pointer to your "Socket s", but the actual value of "s" at the time you're passing it.

To simplify things and eliminate confusion, I'd just remove your forward declaration of "Socket s;" and make your first line in the loop "Socket s = server.accept();".

jefflunt
  • 33,527
  • 7
  • 88
  • 126
ziesemer
  • 27,712
  • 8
  • 86
  • 94
  • 1
    normalocity - http://stackoverflow.com/questions/589919/does-java-pass-by-reference , http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html , and others confirm that Java does first pass by value. – ziesemer Dec 03 '11 at 15:11
  • Exactly, Java passes first by value, then by reference. :-) – ziesemer Dec 03 '11 at 15:15
  • We could force a pass-by-reference by passing a "container" which gets resolved by value, maintaining the value as the actual reference. I.E., Socket[] socketHolder = new Socket[1]; socketHolder[0] = s. If the OP then used socketHolder[0] for everything instead of simply "s", then he really would be passing the socket by reference, and would have problems. – ziesemer Dec 03 '11 at 15:26
  • 1
    So, um. I'm going to take a big, fat, slice of humble pie here. I get it. You're correct. I've removed my answer and comments. Wow, I really got on fire there. I also removed my down vote. My apologies - I see the difference now. We can safely delete this comment thread, since it's no longer relevant. – jefflunt Dec 03 '11 at 15:50
  • normalocity - no problem, apologies accepted! I'm glad to see people get so passionate about the language now and then. :-) – ziesemer Dec 03 '11 at 15:52