0

I am writing a server in Java, which is multithreaded. I have three main active threads that I build and start from my main method:

public class Run{
     public static void main(String[] args){
        try{
            /*
             *  Definition and initialization of "server," "time," and 
             *  "commands" variables not shown.
             */

            new Thread(server).start();
            new Thread(time).start();
            new Thread(commands).start();
        }catch(FileNotFoundException unfound){
            /* Exception code not shown */
        }catch(IOException ioe){
            /* Exception code not shown */
        }
     }
}

My commands thread is used, for example, for stopping the server by have the input "q" into the console window. commands's run method is defined as so:

public void run(){
    while(server.running.get()){
        try{
             String next = scan.nextLine();
             if(next.equalsIgnoreCase("q")){
                  server.shutdown();
                  close();
             }else
                  System.out.println(LocalDateTime.now() + " - Unknown command.");
        }catch(IOException ioe){
             System.out.println(LocalDateTime.now() + " - The commands thread has produced an exception.");
        }
    }
}

*Where scan is defined as: Scanner scan = new Scanner(System.in);

When I run my server all my threads work, except the commands thread as the console is not accepting inputs.

I then realized, if I waited for my server thread (this is the thread I most care about) to join up with my main (static method) thread, my commands thread then worked. Meaning the console accepted inputs if I changed my main method code to this:

Thread t1 = new Thread(server);
t1.start();
new Thread(time).start();
new Thread(commands).start();
try{
    t1.join();
}catch(Exception e){
    e.printStackTrace();   
}

Now to my question. Why does console input only work if the main thread is still active? I honestly do not need my main thread anymore, so letting it terminate would be just fine.

Is there something I am doing incorrectly here with just defining my threads without a name? I am able to terminate each thread nicely as they are interweaved with each other and everything works just except my commands thread.

EDIT: I really appreciate all of the answers regarding a fix to this issue but what I am really after is the reason of why this is happening.

The server thread spirals off and does it own thing (i.e. constantly looking for new connections and establishing new environments for those connections) and the renewal thread goes off and does its own thing as well (i.e. this is used for renewing my quota count as I am using a google API). Other than that, the above code gets the point across on what I am doing.

Code Doggo
  • 1,700
  • 4
  • 25
  • 51
  • We don't see "scan" reference lifecycle in your code. Don't you close `System.in` or `scan` reference before reading from ? – LoganMzz Oct 06 '15 at 23:20
  • @LoganMzz See the close() method there? That is the closing of the scan object. My server thread has the ability to close it too if it terminates. – Code Doggo Oct 06 '15 at 23:59
  • 1
    without more relevant code, there's not much anyone can do to help. – jtahlborn Oct 07 '15 at 00:14
  • @jtahlborn What are you talking about? The question is simple, you don't need to see anymore code as it is not relevant to explaining why after the main thread finishes executing its code that the console input stops. If I included anymore code it would clutter my point and is not relevant at all as it is just implementation details that are not imperative to answering the question. – Code Doggo Oct 07 '15 at 17:24
  • Well, a simple test of the concept on my box has a separate thread reading input just fine. my guess is that something _else_ you are doing is causing the issue. however, you aren't showing enough "else", therefore no one can help you find the problem. – jtahlborn Oct 07 '15 at 17:34
  • what version of java are you using? – jtahlborn Oct 07 '15 at 17:35
  • @jtahlborn Logan Mzz provided an answer below, which is basically what I think you are doing except I put all the console input stuff in another class and then created a thread from that (which is the same type of idea as below). I tested his code and the console didn't allow any input. Can I see your code? Can you upload a screen shot and post a link to it? – Code Doggo Oct 07 '15 at 17:37
  • @jtahlborn Java 1.8.0_31 – Code Doggo Oct 07 '15 at 17:38
  • Sure, example code here: http://pastebin.com/nfSbJ99p ran it on java 6, 7, and 8 and it worked just fine (on linux). – jtahlborn Oct 07 '15 at 19:24
  • Give a [MVCE](http://stackoverflow.com/help/mcve), launch procedure, user action and observed result ... We can't help w/o more information. – LoganMzz Oct 07 '15 at 19:38

4 Answers4

1

You should have your commands thread be your main thread. Just put this in main() after everything else is started:

commands.run();
whoKnows
  • 909
  • 1
  • 9
  • 26
  • That is a fix to this problem, but do you know why is doesn't work on a separate thread when the main thread ends (well I believe it ends)? – Code Doggo Oct 06 '15 at 22:43
0

I don't see any problem with reading from another thread while main is gone away:

public class IOWithoutMain {

  public static void main(String[] args) {
    RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
    System.out.printf("%s %s %s (%s)%n",
        runtime.getVmVendor(),
        runtime.getVmName(),
        System.getProperty("java.version"),
        runtime.getVmVersion());
    new Thread() {
      public void run() {
        try {
          sleep(10_000);
          System.out.print("Enter input: ");
          InputStreamReader isr = new InputStreamReader(System.in);
          BufferedReader br = new BufferedReader(isr);
          System.out.println(br.readLine());
        } catch (InterruptedException|IOException e) {
          e.printStackTrace();
        }
      }
    }.start();
  }
}

Console :

Oracle Corporation Java HotSpot(TM) 64-Bit Server VM 1.8.0_60 (25.60-b23)
Enter input: Test
Test
LoganMzz
  • 1,523
  • 2
  • 17
  • 31
  • Well when I do do this it does not work. My console does not accept any inputs from the user. In addition, I tested your above code and it doesn't work. The console ceases to accepted any input. – Code Doggo Oct 07 '15 at 17:32
-1

JVM takes care about main thread and IO streams. You can try to keep input stream intact by saving/hiding its actual value in the main thread (usual tests approach):

InputStream consoleInput = System.in;
System.setIn(new ByteArrayInputStream(new byte[0]));
ursa
  • 3,680
  • 1
  • 19
  • 36
  • The line "System.in = new ByteArrayInputStream(new byte[0]);" does not compile for me. In addition, it doesn't make sense that I would have to do this. The IO stream should not stop just because the main (static method) thread finishes its code. – Code Doggo Oct 07 '15 at 17:27
  • Use Sysrem.setIn() or Runtime.getRuntime().setIn(). Classic rule - "who open, that closes" in action - app starter opens streams, runs main method, closes streams. Indeed this seems to be an incorrect behavior and you can report it as bug to your JVM provider. – ursa Oct 07 '15 at 17:47
-2

If you want the main thread to terminate without terminating the JVM (and so your other threads) you can use the daemon threads.

Have a look at this link: What is Daemon thread in Java?

PS: remember that having threads which don't terminate can be dangerous especially when they use resources.

Community
  • 1
  • 1
gmcontessa
  • 538
  • 3
  • 10
  • Wait I am confused, does my main thread terminate above (without the join()) or does it stay around until the other threads finish? If it stays around then why doesn't console input work? – Code Doggo Oct 06 '15 at 22:41
  • Having only daemon threads make the JVM to terminate. You have to use "non-daemon" (by default) thread to make the JVM keep alive. – LoganMzz Oct 06 '15 at 23:13
  • Logan is right. I actually got it wrong. The JVM would kill any daemon thread without waiting for them to finish gracefully – gmcontessa Oct 07 '15 at 00:00