【问题标题】:Java thread stuck after join加入后Java线程卡住
【发布时间】:2016-05-16 22:34:06
【问题描述】:

我有这个 Transmitter 类,它包含一个 BufferedReader 和一个 PrintWriter。这个想法是,在主类上,使用 Transmitter.receive() 和 Transmitter.transmit() 到主套接字。问题是:

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

线程更改了“outputMessage”值,我可以使用辅助方法获得该值。问题是,没有加入,我的客户得到了 outputMessage,但我想在我的主类上多次使用它,如下所示:

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

但是加入这个 system.out 永远不会执行,因为trans1.receive() 被卡住了......有什么想法吗?

编辑1:这里是发射器类https://titanpad.com/puYBvlVery

【问题讨论】:

  • 不幸的是,该问题无法重现。您介意发布一个可运行的代码吗?
  • 唯一的循环 while((res = input.readLine()) != null) ,但它不是空的,因为我的 erlang 服务器正在通过套接字发送东西。证据是,如果我删除 'join()' 它会起作用:/
  • 我认为你在线程中的while循环永远不会结束;当它用完输入时,它会阻塞。所以线程永远不会结束,连接永远不会发生。发送完数据后,另一端是否关闭套接字?
  • 如果不是null,那么你的线程永远不会停止,因为循环不会退出。所以你永远不会回到主线程;..
  • 不,另一端是我自己用erlang写的服务器。并且主进程,服务器本身,与套接字建立连接并且永远不会关闭。问题是,没有加入,消息被发送和接收,但如果我想使用相同的 trans1.receive() 它输出另一条消息,而不是当前的(从具有扫描仪类的用户接收)。跨度>

标签: java multithreading concurrency java-threads


【解决方案1】:

您可以发送\n;这并不意味着您会在 Java 代码中看到它。

正如Javadoc for BufferedReader.readLine()(强调我的)中所说:

(返回)包含行内容的字符串,不包括任何行终止符

所以"\n" 永远不会被退回。

【讨论】:

  • 是的,它不返回“\n”,但读取该行直到它得到一个“\n”,这就是我正在做的事情,服务器发送“消息\n”,所以读者阅读并打破循环。但即便如此,它似乎永远都在循环中
  • 请阅读报价:该方法不会返回您发送的行终止符。如果您发送 just "\n",它将返回 ""
  • 是的,我认识Andy,但我不想要“\n”,“\n”是通过erlang方法发送到套接字的。 Erlang 发送“string\n”,receive() 读取该行直到“\n”并中断循环。当循环中断时,我想要消息的那个值。
  • 我不太清楚该怎么说清楚:res.equals("\n") 永远不可能是真的。如果您不想要它,请不要检查它。
  • 即使有可能,您真的希望outputMessage 具有"\n" 的值吗?
【解决方案2】:

这样做:

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

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

将创建一个新线程,然后等待它完成工作并完成。因此它或多或少与直接做一样:

doSomeWork();

新线程在这里没有任何实际用途。

另外,额外的线程引入了同步问题,因为在您的代码中您不能确保变量是同步的。

第三,你的线程在一个循环中不断地从输入中读取行,直到没有更多要读取的内容,除非另一方关闭流,否则它将阻塞 readLine() 调用。你在 getOutput() 中看到的将是一条随机线,恰好在你看的那一刻就在那里,下次你看它可能是同一行,或者是完全不同的行;有些行会被立即读取并忘记,而您不会从主线程中注意到它。

当您实际上需要从输入中获取新行消息时,您可以直接在主线程中调用 input.readLine(),您不需要额外的阅读器线程。您可以按照 yshavit 的建议将读取的消息存储到队列中,如果需要的话,例如出于性能原因,最好在消息可用时立即读取它们并将它们准备好在内存中。但是,如果您只需要一条一条地阅读消息,那么您只需在真正需要时调用 input.readLine() 即可。

【讨论】:

  • 哇,这是一个非常有趣的观察。所以辅助类上的线程是哑的并且:trans1.receive();而(trans1.getOutput() == null); System.out.println("消息:" + trans1.getOutput());不需要吗?问题是,我使用扫描仪从用户那里获取输入,根据那个答案我向套接字发送一个字符串,然后服务器处理并发送响应。我应该怎么办?只在主客户端类上使用 readLine() 吗?非常感谢您的分析...非常感谢
  • 你似乎知道很多。老实说,我的未来取决于这项工作的质量,您会考虑进行 5 分钟的代码审查吗?如果您不免费提供,我理解,在此先感谢。
  • @JoãoVilaça:如果您有兴趣,这里有一个 Code Review 网站(请参阅本页底部的链接)。如果您确实使用它,请务必阅读他们的主题规则,以便充分利用它。
  • 我不知道,谢谢 :) 但是哦,好吧,我真的没有时间花在这上面,我至少需要让它工作,但是是的,我很想知道如果我正在做一些非常愚蠢或不必要的事情......
猜你喜欢
  • 2020-09-03
  • 2021-12-31
  • 1970-01-01
  • 1970-01-01
  • 2020-11-09
  • 1970-01-01
  • 2018-03-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多