2012-06-08 88 views
1

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

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

+0

'SETACTIVE( ...)'设置'听'的价值? – Gray

+0

不,他们只是在我的班级里宣布为常规私人布尔人。我没有使用volatile,因为我认为对象是在多个线程之间共享的,而且我不需要锁定,因为它不是一个复杂的操作,多个线程同时“争夺”访问权限。 – swiftcode

+0

@Gray是的,它的确如此。它只是这个变量的二传手。 – swiftcode

回答

3

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

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

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

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

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

重要的是要认识到,它是重要的是不要只是会发生什么“同时”在某个线程程序。这也与内存缓存有关。接受线程可能在一分钟前向clientSocketsArrayList1添加了一些内容,如果列表未以某种方式同步,另一个线程可能不会看到这些更改。更糟糕的是,ArrayList的某些部分可能已在内存中更新,但不会导致异常的其他部分更新。为了得到一个同步采集,您应该创建ArrayList这样的:

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

听起来像是你应该阅读一些关于为什么同步是必须的文件:

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

+0

serverSocket在那里创建,但它主要是一个重新实例化,因为它首先在run()方法中初始化(在首次创建共享时)。 – swiftcode

+0

Reinstantiation仍需要同步@Lovato。如果任何字段的更改被多个线程更改,则需要对其进行同步。此外,构造函数优化周围存在很多复杂性,可能会导致构建套接字但未完全初始化。如果可以的话,你应该避免在一个线程中构建它并在另一个线程中使用它。 – Gray

+0

clientSockets是客户端套接字的ArrayList。当我禁用共享时,我必须关闭连接到该共享的所有客户端,因此我将它们存储在集合中,调用closeAllConnections()并关闭每个客户端的所有连接,然后将它们从列表中删除。 – swiftcode