java - 多线程和Java Swing问题

标签 java multithreading swing

您好,我有一个运行良好的 GUI 应用程序。我创建了一个套接字服务器。当我在程序中创建服务器类的新对象时,GUI 应用程序停止响应。

这是我的服务器类。如果我这样做

Server s = new Server();

在我的主应用程序中它停止工作。我应该如何添加它?开新线程?我试过了

Thread t = new Thread(new Server());
t.start();

但问题依然存在。拜托,我会感谢你的帮助。

package proj4;

import java.net.*; 
import java.io.*; 

public class Server implements Runnable { 
    ServerSocket       serverSocket = null;
    Socket             clientSocket = null;
    ObjectOutputStream out          = null;
    ObjectInputStream  in           = null;
    int                port;
    static int         defaultPort  = 30000;
    boolean            isConnected  = false;
    Thread             thread;
    DataPacket         packet       = null;

    public Server(int _port) {
        try {
            serverSocket = new ServerSocket(_port);
            serverSocket.setSoTimeout(1000*120);  //2 minutes time out     
            isConnected = true;
            System.out.println("server started successfully");
            thread = new Thread(this);
            thread.setDaemon(true);
            //thread.run();
        } catch (IOException e) {
            System.err.print("Could not listen on port: " + port);
            System.exit(1);
        }
        try {
            System.out.println("Waiting for Client");
            clientSocket = serverSocket.accept();
            System.out.println("Client Connected");
            thread.run();
        } catch (IOException e) {
            System.err.println("Accept failed.");
            System.exit(1);
        }
        try {
            out = new ObjectOutputStream(clientSocket.getOutputStream());
            System.out.println("output stream created successfully");
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            in = new ObjectInputStream(clientSocket.getInputStream());
            System.out.println("input stream created successfully");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public Server() {
        this(defaultPort); //server listens to port 30000 as default
    }

    public void run() {
        System.out.println("Thread running, listening for clients");//debugging purposes
        while (isConnected) {
            try {
                packet = this.getData();
                Thread.sleep(0);
            } catch(InterruptedException e) {
                e.printStackTrace();
            }
        }
    } 

    public DataPacket getData() {
        try {
            packet = (DataPacket)in.readObject();
        } catch (Exception ex)  {
            System.out.println(ex.getMessage());
        }
        return packet;
    }

    public void sendData(DataPacket dp) {
        try {
            out.writeObject(dp);
        } catch (IOException e) {
            e.printStackTrace();
        } 
        try {
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void closeConnection() throws IOException {
        out.close(); 
        in.close(); 
        clientSocket.close(); 
        serverSocket.close(); 
    }
} 

最佳答案

您的 Server 构造函数可能无限期地阻塞在 accept() 中。

关于 Swing 程序的两件事:

  1. 永远不要在 Swing 事件线程中执行任何长时间的任务,并且,
  2. 切勿在 Swing 事件线程之外操作任何 Swing 对象,除非所使用的方法被明确记录为线程安全的。

这意味着,如果服务器是从 Swing 事件线程启动的——也就是说,如果它是为了响应按钮单击等而启动的——那么是的,您必须为您的服务器对象生成另一个线程。否则,您保证 Swing 事件线程将被阻塞,直到您的线程退出。

您说即使您为服务器生成另一个线程,您的应用程序仍会停止响应?确保您调用的是 Thread.start() 而不是 run(),否则您仍然会意外地在自己的线程中实际运行“新线程”而阻塞自己.

注意事项:

  1. 我看到您在 run() 循环中执行了 Thread.sleep(0);。这不能保证做任何事情。如果你有一个单 CPU 机器,这可能会被公平地实现为一个空操作,允许同一个线程继续运行。
  2. 您真的希望 isConnectedvolatile —— 否则无法保证除了更改它的线程之外的任何线程都会看到对此变量的更改.
  3. 您无需在任何地方将 isConnected 设置为 false,因此您的 run() 将一直运行,直到 JVM 停止或该线程出现 RuntimeException。<
  4. It is discouraged在构造函数中启动线程。 (参见 Java Concurrency In Practice。)
  5. 在进入线程的run() 方法之前,您不想在ServerSocketaccept!否则您的构造函数将阻塞等待连接并且不会将控制权返回给事件线程!
  6. 您的构造函数中有以下代码:

您的代码是:

thread = new Thread(this);
thread.setDaemon(true);
//thread.run();

当您没有注释掉 thread.run() 时,您没有开始一个新线程!为此,您需要执行 thread.start()。相反,您在调用构造函数的同一个线程中运行这个新线程(由于上面的原因 #3,它永远不会停止)。您现在编写代码的方式会记录所有 IOExceptions,但会被吞没。您可能希望在任何 IOException 以及 closeConnection() 中将 isConnected 设置为 false

关于java - 多线程和Java Swing问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/720244/

相关文章:

java - 使用 retrofit2 和 RxAndroid 从 Spring WebFlux 获取响应

java - Android 从文本文件解析数字时出现 Invalid Int 错误

java - 如何将字符串中的每个字符转换为8位int? java

c++ - 为什么此代码不创建竞争条件?

java - 有效的重新排序 - 在新的 JMM 下

swing - JMeter GUI - 无法拖放到层次结构中的最后一个元素

java - 获取不同区域用户当前客户端日期和时间的方法

java - 如何让一个方法等待另一个类的输入?

Java:如何识别特定的字符串

java - Jframe 内容不显示