【问题标题】:What type of message passing should I use in this situation? GUI sending commands to a Thread; Java在这种情况下我应该使用什么类型的消息传递? GUI 向线程发送命令;爪哇
【发布时间】:2014-01-18 02:22:58
【问题描述】:

我有一个称为 mainFrame 的 JFrame,它是在使用我的程序时向用户显示的主要 JFrame。

程序创建一个到服务器的 Socket,并在它和服务器之间来回发送消息。

我正在尝试创建一个线程来处理连接。因此,当用户单击“连接”时,线程将设置 Socket 以及相关的输入和输出流。然后我希望线程等到 JFrame 向它发送一个命令,该命令只是一个字符串,它应该打印到套接字的输出流。线程将发送命令,读取响应,然后等待另一个命令。

我想我可以设置一个队列,我可以将命令“存放”到其中,然后当线程处理它时,它可以将第一个命令从队列中拉出并随心所欲地处理它。

有什么想法吗?

另外,目前我将参数this 传递给线程,以便它可以访问JFrame 中的函数以将输出打印到文本区域。这可以吗?我可以允许线程调用产生它的 JFrame 中的方法吗?

【问题讨论】:

    标签: java multithreading swing sockets


    【解决方案1】:

    建议:

    • Swing GUI 可以将文本发送到 Socket,我认为不需要任何额外的线程,因为这是非阻塞的。
    • 是的,需要一个单独的线程来等待 Socket 并读取传入的数据。为此,您可以使用 Scanner 或 BufferedReader。
    • 然后在遇到任何换行符时将文本从该线程发送到 GUI。这需要在 EDT 上完成,可能通过 SwingWorker 与 PropertyChangeListener 的发布/处理方法对。
    • 是的,后台线程可以调用 GUI 上的方法,但始终注意在 Swing 事件线程上执行此操作,方法是将代码放在 Runnable 中并通过 SwingUtilities.invokeLater(...) 将其排队到 Swing 事件队列中。李>

    编辑
    你评论:

    “在美国东部时间”是什么意思?

    EDT = Swing Event Dispatch T线程,执行所有 Swing 绘图和用户交互的主要 Swing 线程。如果你阻止了这个线程,你就阻止了 Swing 的所有显示和 UI,基本上冻结了你的程序。详情请见Concurrency in Swing

    还说向套接字发送文本是阻塞的,我该如何为其设置命令队列?

    我不明白这个问题,因为据我了解,在套接字上发送信息不应该阻塞。

    【讨论】:

    • “在美国东部时间”是什么意思? // 还说向socket发送文本是阻塞的,我该如何为其设置命令队列?
    • 嗯,假设我有一个线程调用一些阻塞方法,例如Socket.accept。在从套接字接受新数据(它在循环中调用 socket.accpet)之间,我如何向该线程发送要执行的命令列表?
    【解决方案2】:

    看这段代码,但必须自己实现参数:

    public class ConnectionThread extends Thread {
        public static final HOST = "www.example.com";
        public static final PORT = 24239;
    
        private String command;
        private boolean lookahead = false;
        private boolean allowChangeLookahead = true;
        private boolean canRetrieveResult = false;
        Private String result;
        orivate Socket s = new Socket(HOST, PORT);
    
        public void run() {
            for(;;) { // Infinite loop
                sleep(500); // Avoid low perfomance related problems.
    
                if(lookahead) {
                    allowChangeLookahead = false;
    
                    try {
                        PrintWriter out = new PrintWriter(s.getOutputStream(), true);
                        BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
                        out.println(command);
                        result = in.readLine();
                        canRetrieveResult = true;
                    } catch(Exception e) {
                        // Something occured...
                    }
    
                    lookahead = false;
                    allowChangeLookAhead = true;
                }
            }
        }
    
        public synchronized void command(String cmd) {
            command = cmd;
    
            for(;;) { // Don't worry, not infinite
                if(allowChangeLookahead) {
                    lookahead = true;
                    break;
                }
            }
        }
    
        public synchronized String getResult() {
            for(;;) {
                if(canRetrieveResult) {
                    return result;
                }
            }
        }
    }
    

    同时,在主序列中......

    ConnectionThread conThread = new ConnectionThread();
    conThread.start();
    // ...
    // Code of method that responds to command
    if(calledCommand) {
        conThread.command(theCommand);
        result = conThread.getResult();
    }
    

    就是这样!还有记得写服务器,需要帮助就问我。

    【讨论】:

    • // ... 连同消息,这是否意味着您在主 GUI 的答案中给出的代码,可以随时运行吗?比如点击按钮?
    • 为什么命令不产生无限循环?,ConnectionThread 中的result 没有声明。 // 所以我认为调用 getResult()command() 会阻塞主 GUI,直到满足 for 循环条件?
    • 抱歉出现错误。我修复了result 问题。并且不要担心循环,因为服务器调用有超时,所以如果询问者正确实现异常处理程序,代码会很快。请记住,command()getResult() 方法是同步的,因此一切都经过验证并且与情况无关。这里发生的是我的代码有一个类似于等候室的东西,这是命令的无限循环
    • getResult 也需要返回类型;抱歉只是强迫症。
    • @BumSkeeter 已修复。感谢您的来信。
    猜你喜欢
    • 2023-03-16
    • 1970-01-01
    • 2012-01-29
    • 1970-01-01
    • 2015-12-02
    • 1970-01-01
    • 2018-11-11
    • 2015-02-13
    • 1970-01-01
    相关资源
    最近更新 更多