【问题标题】:Keep console input active without main thread? (Java)在没有主线程的情况下保持控制台输入处于活动状态? (爪哇)
【发布时间】:2015-10-06 22:13:41
【问题描述】:

我正在用 Java 编写一个服务器,它是多线程的。我从我的 main 方法构建和启动了三个主要活动线程:

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 */
        }
     }
}

我的 commands 线程用于,例如,通过在控制台窗口中输入“q”来停止服务器。 命令运行方法是这样定义的:

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.");
        }
    }
}

*其中scan定义为:Scanner scan = new Scanner(System.in);

当我运行我的服务器时,我的所有线程都可以工作,除了 commands 线程,因为控制台不接受输入。

然后我意识到,如果我等待我的 server 线程(这是我最关心的线程)join 我的 main(静态方法)线程,然后我的 commands 线程开始工作。这意味着如果我将我的 main 方法代码更改为此控制台接受输入:

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

现在我的问题。为什么控制台输入只有在 main 线程仍处于活动状态时才有效?老实说,我不再需要我的 main 线程,所以让它终止就可以了。

我在这里做错了什么,只定义了没有名字的线程吗?我能够很好地 终止每个线程,因为它们相互交织,并且除了我的 commands 线程之外一切正常。

编辑: 我非常感谢有关解决此问题的所有答案,但我真正追求的是发生这种情况的原因

server 线程螺旋式关闭并做自己的事情(即不断寻找新连接并为这些连接建立新环境),renew 线程关闭并执行它自己的东西也是如此(即,当我使用谷歌 API 时,它用于更新我的配额计数)。除此之外,上面的代码说明了我在做什么。

【问题讨论】:

  • 我们在您的代码中看不到“扫描”引用生命周期。阅读之前不要关闭System.inscan 参考吗?
  • @LoganMzz 看到 close() 方法了吗?即关闭扫描对象。如果我的服务器线程终止,它也可以关闭它。
  • 没有更多相关代码,没有人能帮上忙。
  • @jtahlborn 你在说什么?问题很简单,您不需要再查看代码,因为它与解释为什么在主线程完成执行其代码后控制台输入停止的原因无关。如果我包含更多代码,它会弄乱我的观点并且根本不相关,因为它只是实现细节,对于回答问题并不是必须的。
  • 好吧,我的盒子上的概念的简单测试有一个单独的线程读取输入就好了。我的猜测是你正在做的事情 else 导致了这个问题。但是,您没有显示足够的“其他”,因此没有人可以帮助您找到问题。

标签: java multithreading server system.in console-input


【解决方案1】:

你应该让你的命令线程成为你的主线程。 一切都启动后,把它放在 main() 中:

commands.run();

【讨论】:

  • 这是解决这个问题的方法,但是你知道为什么当主线程结束时它在单独的线程上不起作用(我相信它结束了)吗?
【解决方案2】:

我认为在 main 消失时从另一个线程读取没有任何问题:

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();
  }
}

控制台:

Oracle Corporation Java HotSpot(TM) 64-Bit Server VM 1.8.0_60 (25.60-b23)
Enter input: Test
Test

【讨论】:

  • 好吧,当我这样做时,它不起作用。我的控制台不接受用户的任何输入。另外,我测试了你上面的代码,它不起作用。控制台停止接受任何输入。
【解决方案3】:

JVM 负责主线程和 IO 流。您可以尝试通过在主线程中保存/隐藏其实际值来保持输入流的完整性(通常的测试方法):

InputStream consoleInput = System.in;
System.setIn(new ByteArrayInputStream(new byte[0]));

【讨论】:

  • 行“System.in = new ByteArrayInputStream(new byte[0]);”不为我编译。此外,我必须这样做是没有意义的。 IO 流不应仅仅因为主(静态方法)线程完成其代码而停止。
  • 使用 Sysrem.setIn() 或 Runtime.getRuntime().setIn()。经典规则——“谁打开,谁关闭”——应用启动器打开流,运行 main 方法,关闭流。事实上,这似乎是一种不正确的行为,您可以将其作为错误报告给您的 JVM 提供商。
【解决方案4】:

如果您希望主线程终止而不终止 JVM(以及其他线程),您可以使用守护线程。

看看这个链接:What is Daemon thread in Java?

PS:请记住,拥有不终止的线程可能很危险,尤其是在它们使用资源时。

【讨论】:

  • 等等,我很困惑,我的主线程是在上面终止(没有 join())还是在其他线程完成之前一直存在?如果它仍然存在,那么为什么控制台输入不起作用?
  • 只有守护线程会使 JVM 终止。您必须使用“非守护程序”(默认情况下)线程来使 JVM 保持活动状态。
  • 洛根是对的。我其实弄错了。 JVM 会杀死任何守护线程而不等待它们优雅地完成
猜你喜欢
  • 2013-11-08
  • 2011-07-13
  • 1970-01-01
  • 2017-10-12
  • 2011-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多