2012-06-08 4 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() reenables которые разделяют.

Проблема заключается в том, что если я отключу общий ресурс, он должен просто закольтать terminate, пока он не будет неопределенным, проверяя значение listening. Когда я устанавливаю listening в true, он должен повторно ввести эту секунду во время цикла и начать прослушивание снова, потому что я открываю сокет сервера (хотя это не связано с этим, я просто говорю, что он должен быть инициализирован снова, потому что я закрываю это когда я отключу эту долю). Однако после отключения он никогда не арендует петлю listening, даже когда вызывается openConnection().

Кто знает, что здесь не верно?

+0

'SetActive (...) 'устанавливает значение' listen'? – Gray

+0

Нет, они просто объявлены как обычные частные булевы внутри моего класса. Я не использовал volatile, потому что я думал, что объекты были разделены между несколькими потоками, и я не требовал блокировок, потому что это не сложная операция, когда несколько потоков «сражаются» за доступ в одно и то же время. – swiftcode

+0

@Gray Да, делает. Это просто средство для этой переменной. – swiftcode

ответ

3

Приведенный код не отображает ошибки. Но вот некоторые комментарии, которые могут помочь.

  • Оба shutdown и listening булевы должны быть volatile. Любые поля, разделяемые между потоками, должны быть как-то синхронизированы, иначе изменения их значений не будут видны другими потоками.

  • serverSocket также должны быть volatile, так как это, кажется, создан вызывающей openConnection() но потребляются в цикле while. Вы могли бы просто установить значение true в openConnection() и иметь serverSocket, полностью управляемый потоком accept.

  • 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

Повторное истолкование еще нужно синхронизировать @Lovato. Любые изменения в любых полях необходимо синхронизировать, если они меняются несколькими потоками. Кроме того, существует большая сложность в оптимизации конструктора, которая может привести к созданию сокета, но не полностью инициализирована. Вы не должны конструировать его в одном потоке и потреблять его в другом, если сможете. – Gray

+0

clientSockets - это ArrayList клиентских сокетов. Когда я отключу общий доступ, я должен закрыть всех клиентов, подключенных к этому ресурсу, поэтому я храню их в коллекции, вызываю closeAllConnections() и закрывает все подключения для каждого клиента, а затем удаляет их из списка. – swiftcode

Смежные вопросы