Как работает синхронизированный оператор в этом случае? - PullRequest
0 голосов
/ 08 октября 2010

Предположим, у меня есть такой класс:

public class Server {

   public static void main(String[] args) {

      Map<Integer, ServerThread> registry = Collections.synchronizedMap(new LinkedHashMap<Integer, ServerThread>());

      ...

      while(true) {
         Socket socket = serverSocket.accept();
         ServerThread serverThread = new ServerThread(id, registry);
         registry.put(id, serverThread);
      }
   }
}

Тогда:

public class ServerThread extends Thread {

   private Map<Integer, ServerThread> registry;
   private int id;

   public ServerThread(int id, Map<Integer, ServerThread> registry) {
      this.id = id;
      this.registry = registry;
   }

   ...

   private void notify() {
      synchronized(registry) {
         for(ServerThread serverThread : registry.values()) {
            serverThread.callSomePublicMethodOnThread();
         }
      }      
   }
}

Я просто хочу убедиться, что registry не будет изменено во время итерациинад ним.Гарантирует ли это синхронизированное отображение?Или мне нужно заявление synchronized.Будет ли синхронизированный оператор вести себя так, как я ожидаю?

Спасибо

Ответы [ 4 ]

5 голосов
/ 08 октября 2010

Вам необходим блок synchronized вокруг цикла.

Подробнее см. JavaDoc .

2 голосов
/ 08 октября 2010

Да, синхронизированный оператор у вас будет работать так, как вы ожидаете.Я бы просто добавил один комментарий, поток, который вы принимаете, к сокетам будет блокироваться в Registry.put (id, serverThread);пока вы находитесь в синхронизированном разделе в другом потоке.Это означает, что ваш сервер не будет обрабатывать какие-либо новые входящие запросы, пока вы обрабатываете уведомление .....

Возможно, вы захотите перенести оператор put (конечно, изменив serverThread на это) на самый первыйстрока метода run метода run ServerThread.Таким образом, вы не будете блокировать входящие соединения, если callSomePublicMethodOnThread завершает работу, занимая много времени.

1 голос
/ 08 октября 2010

Чтобы упростить все, я бы использовал ConcurrentHashMap (http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ConcurrentHashMap.html), поэтому вам не нужно использовать блок синхронизации в цикле, потому что concurrentHashMap использует итератор другого типа (не итератор, не сбойный), и он не будет работать concurrentModificationException, вы также получите лучшую производительность.

0 голосов
/ 28 февраля 2012

В коде есть одна проблема, вы не можете определить свой метод как "private void notify ()", потому что "notify ()" - это метод, определенный в классе Object

...