【问题标题】:Multithreaded return value多线程返回值
【发布时间】:2013-12-09 13:53:59
【问题描述】:

我正在开发一个使用套接字的 Java 项目。由于 Socket 方法是阻塞方法,我不得不制作一个多线程应用程序。

到目前为止,我能够从其他应用程序读取传入的字节。我将它们写入 StringBuilder。我的问题是如何将此字符串返回到我的主线程。我在想一个事件之类的东西,我可以在 Socket-Thread 读完后立即调用它。

我很高兴有任何想法。

public class SocketRunnable implements Runnable {

private final Socket _socket;


public SocketRunnable(Socket socket){
    this._socket = socket;
}

@Override
public void run() {
    StringBuilder sb = new StringBuilder();
    try {
        BufferedReader bufferedReader = 
                new BufferedReader(
                    new InputStreamReader(
                        this._socket.getInputStream()));


    char[] buffer = new char[100];
    int amountOfBytes = bufferedReader.read(buffer, 0, 100); // blocks until the message is received.
    String message  = new String(buffer, 0, amountOfBytes);
    sb.append(message);

    } catch (IOException ex) {
        Logger.getLogger(SocketRunnable.class.getName()).log(Level.SEVERE, null, ex);
    }
    finally{

        // Return (!)
    }

}

【问题讨论】:

  • 为什么要把它返回到你的主线程?你需要对这个返回的字符串做什么?
  • 我想让它在文本框中可见。所以我想把这个字符串返回给处理这个人的 mainThread。
  • 如果您在 Swing 上,则使用 EventQueue.invokeLater 将事件发布到 Event-Dispatch 线程。但我怀疑您的问题在于切换线程:它在于从外部线程访问适当的对象。

标签: java multithreading swing sockets


【解决方案1】:

我的问题是如何将此字符串返回到我的主线程。

你不能——不是因为任何技术障碍,而是因为它在概念上没有意义。您的主线程已经开始运行,并且您的返回值有意义的上下文丢失了。

所以,要么:

  • 你的主线程必须阻塞才能接收结果(但是多线程的意义何在);

  • 您的主线程已经以面向事件的方式从头开始设计,并且有一个外部 事件循环,它从队列中取出事件并处理它们(如果您正在构建一个 GUI 应用程序)。

更有意义的是使结果对其他代码可用。这一切都可能发生在同一个线程中,即接收的线程。您可以通过简单地调用适当的方法来实现这一点。因此,在您的设计中要解决的问题是,如何使具有该方法的实例可用于在读取线程中执行的代码。

【讨论】:

  • +1 我假设他将从主线程轮询它。因此,在SocketRunnable 上使用 volatile 字段可能就足够了。
  • 我正在使用 MVC 模式,并且我的 Socket-Thread 在模型类中工作。到目前为止,整个主线程都是基于事件的,但我不熟悉外部事件循环。也许我已经在实施这个,但不是有意识的。也许 SwingWorker 是更好的选择?
  • 是的,您可以将SwingWorker 用于异步任务,这可以很好地解决样板问题。
【解决方案2】:

您可以将Callable 接口与Executors 结合使用。 你可以在这里阅读:

可调用:

http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Callable.html

执行者:

http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html

只需使用您的 SocketRunnable 类实现可调用接口(有一种方法 - call(),它会在完成时将值从一个线程返回到另一个线程)。

【讨论】:

    【解决方案3】:

    要将结果显示到 Swing TextField 中,您可以处理结果,一旦您有了字符串就可以:

    final String msg=???; // Insert your string here
    
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            textBox.setText(msg);
        } 
    });
    

    invokeLater 调用会将您转到正确的线程以修改文本字段的内容。

    【讨论】:

      【解决方案4】:

      将结果字符串写入阻塞队列,并让主线程polltake从该队列中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-10-22
        • 1970-01-01
        • 2017-01-23
        • 1970-01-01
        • 1970-01-01
        • 2013-11-06
        • 2012-02-27
        相关资源
        最近更新 更多