在重新评估条件时,为什么不这样做?

时间:2012-06-08 12:59:35

标签: java multithreading sockets loops while-loop

我有两个条件,一个在另一个里面,用布尔来控制它们。基本上,一个用于终止共享,另一个用于侦听连接。用户可以选择禁用共享,在这种情况下,服务器停止侦听但不会终止。如果用户选择终止,则两个布尔值都设置为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 cicle,测试listening的值。当我将listening设置为true时,它应该重新进入第二个while循环并再次开始侦听,因为我确实打开了服务器套接字(尽管它与此无关,我只是说它必须再次初始化,因为我在禁用共享时关闭它)。但是,禁用后,即使调用listening,它也永远不会租用openConnection()循环。

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

1 个答案:

答案 0 :(得分:3)

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

  • shutdownlistening布尔值都必须为volatile。线程之间共享的任何字段都需要以某种方式同步,否则其他线程将无法看到对其值的更改。

  • serverSocket也需要volatile,因为它似乎是由openConnection()的调用者创建的,但在while循环中使用。您可以考虑在openConnection()中将活动设置为true,并使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