1

我有两个 while 条件,一个在另一个里面,用布尔值来控制它们。基本上,一个用于终止共享,另一个用于侦听连接。用户可以选择禁用共享,在这种情况下,服务器会停止侦听,但不会终止。如果用户选择终止,则两个布尔值都设置为 false 并且循环结束。

这是我的代码:

        public void run() {
            while (!terminate) {  
                while (listening) {
                    try {
                        // accept connection -> create a new thread for each client
                        ClientServerShareInstance clientServerShareInstance = new ClientServerShareInstance(serverSocket.accept(), ui);
                        Thread clientServerThread = new Thread(clientServerShareInstance);
                        clientSockets.add(clientServerShareInstance);
                        connectedClients++;
                        clientServerThread.start();
                    } catch (IOException ex) {
                    }
                }
            }
        }

        public void closeAllClientConnections() {
            for (Iterator it = clientSockets.iterator(); it.hasNext();) {
                ClientServerShareInstance clientServerShareInstance = (ClientServerShareInstance) it.next();
                clientServerShareInstance.closeAllConnections();
                it.remove();
            }
            try {
                this.serverSocket.close();
            } catch (IOException ex) {}
            this.setActive(false);
            this.connectedClients = 0;
        }


        public void openConnection() {
            try {
                serverSocket = new ServerSocket(portNumber, 0, Inet4Address.getLocalHost());
                setActive(true);
            } catch (IOException ex) {}
        }
    }

closeAllClientConnections()方法禁用共享(不终止它),并openConnection()重新启用该共享。

问题是,如果我禁用共享,它应该只是terminate无限期循环 while cicle,测试listening. 当我设置listening为 时true,它应该重新进入第二个 while 循环并再次开始侦听,因为我确实打开了服务器套接字(虽然它与此无关,但我只是说它必须再次初始化,因为我关闭它时我禁用共享)。但是,禁用后,它永远不会租用listening循环,即使openConnection()被调用也是如此。

有人知道这里有什么问题吗?

4

1 回答 1

3

没有足够的代码显示任何错误。但这里有一些可能会有所帮助的评论。

  • shutdown和布尔值都listening需要是volatile。线程之间共享的任何字段都需要以某种方式同步,否则其他线程将看不到对其值的更改。

  • serverSocket也需要,volatile因为它似乎是由调用者创建但在循环中openConnection()消耗的。while您可能会考虑将 active 设置为 true inopenConnection()serverSocket完全由接受线程管理。

  • clientSockets看起来是一个集合。这将需要一个同步连接,因为它看起来被多个线程访问。同样,更好的模式是closeAllClientConnections() 调用设置一个布尔值,线程本身将执行关闭。这消除了使用集合等的任何竞争条件。

  • 看起来如果你是! terminating你的接受线程将会旋转。至少你应该放一些Thread.sleep(100)或一些东西来减慢它。等待/通知会更好。

重要的是要意识到这不仅仅是线程程序中“同时”发生的事情。它也与内存缓存有关。接受线程可能在clientSockets ArrayList1一分钟前添加了一些东西,如果列表没有以某种方式同步,另一个线程可能看不到这些更改。更糟糕的是,某些部分ArrayList可能已在内存中更新,而其他部分可能会导致异常。要获得同步的集合,您应该创建您的ArrayList喜欢:

List<...> clientSockets = Collections.synchronizedList(new ArrayList<...>());

听起来您应该阅读一些有关为什么需要同步的文档:

http://docs.oracle.com/javase/tutorial/essential/concurrency/sync.html

于 2012-06-08T13:05:24.163 回答