【问题标题】:Thread not stopping until Thread.join() on Windows线程直到 Windows 上的 Thread.join() 才停止
【发布时间】:2017-01-24 23:49:21
【问题描述】:

stopServer() 服务器方法在 Mac、Linux 和 UNIX 计算机上完美运行,但是当我尝试在 Windows 上关闭时,我发现每个至少需要一秒钟由于ServerSocket 超时而关闭的套接字。我希望它们像在 Linux、Mac 等中一样一次性关闭,而不是在我调用 Thread.join() 时一次关闭。

服务器代码

public class FileServer {

    private ArrayList<Thread> sockets = new ArrayList<>();
    private ServerSocket fileServer;

    public void startServer(int port, int maxThreads, int timeout) throws IOException {

        fileServer = new ServerSocket();
        fileServer.setPerformancePreferences(1, 0, 1);
        fileServer.bind(new InetSocketAddress(port));

        for (int threads = 0; threads < maxThreads; threads++) {
            sockets.add(new Thread(new ServerInit(fileServer, timeout)));
            System.out.println("Socket " + threads + " initialized...");
        }

        for (int socket = 0; socket < sockets.size(); socket++) {
            (sockets.get(socket)).start();
            System.out.println("Socket " + socket + " started!");
        }
    }

    public void stopServer() {
        if (fileServer.isBound()) {
            for (int thread = 0; thread < sockets.size(); thread++) {
                sockets.get(thread).interrupt();
            }
            for (int thread = 0; thread < sockets.size(); thread++) {
                try {
                    if (sockets.get(thread).isAlive()) {
                        sockets.get(thread).join();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

class ServerInit implements Runnable {
    private ServerSocket server;
    private int timeout;

    public ServerInit(ServerSocket server, int timeout) {
        this.server = server;
        this.timeout = timeout;
    }

    public void run() {
        while (!Thread.interrupted()) {
            try {
                server.setSoTimeout(1000);
                Socket client = server.accept();
                client.setSoTimeout(timeout);
                processRequest(receiveRequest(client), client);
                client.close();
            } catch (SocketTimeoutException ste) {
            } catch (IOException io) {
                io.printStackTrace();
            }
        }
        System.out.println("Socket closed");
    }
}

为什么线程在退出while 循环之前要求我加入它们?我已经测试并且确信每个线程都在启动并且每个线程都被正确地中断了。

另外,如果我将System.out.println() 放入while 循环中,则只有一个线程会正确打印。

编辑

我非常清楚它必须等待accept 超时。这是有意的,因此只有一秒钟的超时。这一切都在其他平台上完美运行。我正在中断所有线程,然后加入它们以确保它们真正停止。我最担心的是为什么这些线程没有按应有的方式同时超时。

【问题讨论】:

  • 您认为这到底是如何工作的?线程在accept,它被中断了。您认为抛出了 InterruptedException 吗?按照惯例,这会清除中断标志,这就是您要检查的全部内容。
  • Javadoc 中没有任何内容表明ServerSocket.accept() 是可中断的,因此您的线程都在等待接受超时。您的代码按设计工作。有趣的是它在某些平台上速度更快,但它在 Windows 上的运行方式并没有错。你的标题毫无意义。
  • 为什么不在 ServerInit 类的 while 循环中使用 volatile 静态变量(信号量)来停止线程而不是检查中断标志?
  • @EJP:在我看来,这应该只会导致总共延迟一秒,而不是每个线程一秒。除非在主线程中对.interrupt() 的调用必须等待每个子线程中的accept() 超时?
  • 我认为您需要更多调试语句以确保您了解事件的确切顺序,即打印每次调用 .interrupt() 之前和之后的时间以及每次调用 @ 之前和之后的时间987654335@ 和在每个线程中检查 .interrupted() 时。编辑您的问题以显示更改并包含输出(对于简单的情况,例如五个线程)。

标签: java windows multithreading sockets


【解决方案1】:

对于 *nix 操作系统,套接字实现不会一直锁定accept

对于 Windows,PlainSocketImpldefines accept as synchronized

protected synchronized void accept(SocketImpl s) throws IOException {
    // ...
}

发生的情况是accept 一次只被一个线程执行。 1 秒超时仅在最终获得锁后被原生 accept 考虑在内。

我无法判断这是否是故意的,您必须在 Java 邮件列表中询问。

【讨论】:

    猜你喜欢
    • 2015-02-12
    • 2014-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多