0

I have this Transmitter class, which contains one BufferedReader and one PrintWriter. The idea is, on the main class, to use Transmitter.receive() and Transmitter.transmit() to the main socket. The problem is:

 public void receive() throws Exception {
      // Reads from the socket
      Thread listener = new Thread(new Runnable() {
        public void run() {
          String res;

          try {
            while((res = input.readLine()) != null) {
              System.out.println("message received: " + res);

              outputMessage = (res);

            if (res.equals("\n")) {
              break;
            }
           }
        } catch (IOException e) {
          e.printStackTrace();
        }
      };
    });

    listener.start();
    listener.join();
  }

The thread changes the 'outputMessage' value, which I can get using an auxiliary method. The problem is that, without join, my client gets the outputMessage but I want to use it several times on my main class, like this:

trans1.receive();
while(trans1.getOutput() == null);
System.out.println("message: " + trans1.getOutput());

But with join this system.out never executes because trans1.receive() is stuck... any thoughts?

Edit 1: here is the transmitter class https://titanpad.com/puYBvlVery

halfer
  • 19,824
  • 17
  • 99
  • 186
João Vilaça
  • 601
  • 1
  • 6
  • 13
  • The problem is not reproducible unfortunately. Would you mind please posting a runnable code. – Yassin Hajaj May 16 '16 at 22:37
  • the only loop while((res = input.readLine()) != null) , but it's not null because my erlang server is sending stuff through the socket. The proof is that if i remove 'join()' it works :/ – João Vilaça May 16 '16 at 22:37
  • I think your while loop in the thread is never ending; when it runs out of input it is blocking. So the thread never ends and the join never happens. Does the other end close the socket when it is done sending data? – antlersoft May 16 '16 at 22:40
  • If it's never `null`, then your thread never stops since the loop does not exit.. So you're never returning to the main thread;.. – Yassin Hajaj May 16 '16 at 22:40
  • No, the other end is a server written in erlang by myself. And the main process, the server itself, establishes connections with the socket and never closes. The thing is, without the join, the messages are sent and received, but if i want to use the same trans1.receive() it outputs the other message, not the current (received from the user with a scanner class). – João Vilaça May 16 '16 at 22:41
  • @JoãoVilaça You'll have to change the nature of your main loop than or remove the join. Why do you need a join in the first time? It is normally used to make sure the first thread finishes before returning to main. What are you expecting to finish here? – Yassin Hajaj May 16 '16 at 22:44
  • Are you sure that `readLine` reads the line ending? – Andy Turner May 16 '16 at 22:44
  • Why not store `trans1.getOuptut()` into a local variable, and then use that variable in the various expression? That's similar to what you do with `String res`, for instance. You read `input.printLine()`, write that to a local variable `res`, and then do several things with it (check it for nullity, print it to stdout, check if it's equal to `"\n"`). – yshavit May 16 '16 at 22:44
  • Yes, my erlang handlers for that always send "\n" in the end, e.g. gen_tcp:send(Socket, "some string\n"). – João Vilaça May 16 '16 at 22:44
  • The idea is: get input from the user through scanner. send that through the socket, get the response, and according to the response, say something to the client. Server is in erlang and client in java. – João Vilaça May 16 '16 at 22:46
  • But keep in mind that you'll still have a racy condition, because you can miss messages or double-read them depending on the timing of when you read and write `outputMessage`. A better option would be to write messages to a thread-safe collection, like a BlockingQueue, and then pull them off in the consuming threads. That's a standard producer-consumer pattern. – yshavit May 16 '16 at 22:46
  • So, should "outputMessage" be volatile? Or should I rewrite all this using Executors? – João Vilaça May 16 '16 at 22:48
  • If the transmitter class is useful to have in your question, would you add it as a code block? We tend to discourage external pasteboards since the links tend to break quick quickly, giving editors more work to do (and sometime rendering questions useless). Thanks. – halfer May 17 '16 at 19:40
  • Well, i was kind of desperate yesterday so i posted on a titanpad, is still online if you want to check, i think there's no need for another fiddle, i think i know what the problem was :/ but thanks man, i really appreciate it! – João Vilaça May 17 '16 at 20:01

2 Answers2

3

You might send \n; that doesn't mean that you will see it in your Java code.

As it says in the Javadoc for BufferedReader.readLine() (emphasis mine):

(Returns) A String containing the contents of the line, not including any line-termination characters

so "\n" will never be returned.

Andy Turner
  • 137,514
  • 11
  • 162
  • 243
  • Yes, it doesn't return "\n", but reads the line UNTIL it gets a "\n", and thats what im doing, the server sends "message\n", so the reader reads and breaks from the cycle. But even then, it seems like it stays on the loop forever – João Vilaça May 16 '16 at 22:49
  • Please read the quote: the method won't return a line terminator that you send. If you send *just* `"\n"`, it would return `""`. – Andy Turner May 16 '16 at 22:50
  • Yes, I know Andy, but I don't want the "\n", the "\n" is sent TO the socket through the erlang method. Erlang sends "string\n", and the receive() read the line until "\n" and breaks from the cycle. And I want that value of the message, when the loop breaks. – João Vilaça May 16 '16 at 22:52
  • I don't quite know how to say it any more clearly: *`res.equals("\n")` can never be true*. If you don't want it, don't check for it. – Andy Turner May 16 '16 at 22:54
  • And even if it were possible, do you really want `outputMessage` to have the value `"\n"`? – Andy Turner May 16 '16 at 22:57
  • Sorry, i'm just too tired, maybe i'm not understading it clearly. So assuming you're correct, how can I get out of the readline? I mean, the thread reads the string till the end and then dies? socket.shutdownInput() ? Do you mind coming to that titanpad link to chat for 2mins? Deadline project, i'm desperate – João Vilaça May 16 '16 at 22:57
  • Why not just break unconditionally? – Andy Turner May 16 '16 at 23:05
  • My teacher had that same loop with that same if, but oh well, I just used break unconditionally, it worked. I will accept your answer, thanks a lot and sorry for all the trouble... – João Vilaça May 16 '16 at 23:08
1

Doing this:

{
  Thread listener = new Thread(new Runnable() {
    public void run() {
      doSomeWork();
    };
  });

  listener.start();
  listener.join();
}

will create a new thread and then wait for it to do its work and finish. Therefore it's more or less the same as just directly doing:

doSomeWork();

The new thread doesn't serve any real purpose here.

Also, the extra thread introduces synchronization problems because in your code you don't make sure your variables are synchronized.

Thirdly, your thread keeps reading lines from the input in a loop until there's nothing more to read and unless the other side closes the stream, it will block on the readLine() call. What you will see in with getOutput() will be a random line that just happens to be there at the moment you look, the next time you look it might be the same line, or some completely different line; some lines will be read and forgotten immediatelly without you ever noticing it from the main thread.

You can just call input.readLine() directly in your main thread when you actually need to get a new line message from the input, you don't need an extra reader thread. You could store the read messages into a Queue as yshavit suggests, if that's desirable, e.g. for performance reasons it might be better to read the messages as soon as they are available and have them ready in memory. But if you only need to read messages one by one then you can simply call input.readLine() only when you actually need it.

jhncz
  • 163
  • 1
  • 8
  • wow, that is a really interesting observation. So the thread on the helper class is dumb and : trans1.receive(); while(trans1.getOutput() == null); System.out.println("message: " + trans1.getOutput()); is not needed? The problem is that, I use the scanner to get input from the user, according to that answer i send a string to the socket, and then the server processes and sends the response. What should I do? just use readLine() on the main client class? thanks a lot for your analysis...I really appreciate it – João Vilaça May 17 '16 at 08:27
  • You seem to know a lot. Honestly my future depends on the quality of this work, would you consider doing a 5minute code review? And I understand if you wouldn't do it for free, thanks in advance. – João Vilaça May 17 '16 at 08:31
  • 1
    @JoãoVilaça: there is a _Code Review_ website if you are interested (see links at the bottom of this page). If you do use it, be sure to read their on-topic rules, so you can get the most out of it. – halfer May 17 '16 at 19:42
  • I didn't knew that, thanks :) But oh well, I have no time to spend on that really, i just needed for it to work at least, but yeah, I was curious to know if i'm doing anything really dumb or unnecessary... – João Vilaça May 17 '16 at 19:59