0

Предположим, у меня есть класс, как это:Как работает синхронизированный оператор в этом случае?

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. Будет ли синхронизированный оператор вести себя так, как я ожидаю?

Благодаря

ответ

5

Вам нужен synchronized блок по контуру.

Для получения дополнительной информации см. JavaDoc.

+0

Спасибо! (требуемые символы) –

2

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

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

+0

Хорошая точка! Я просто опубликовал упрощенный пример. В моем фактическом коде я запускаю отдельные потоки в цикле, и поэтому фактическая обработка выполняется в этих потоках. Но вы хорошо знаете. Я буду двигаться в любом случае! Благодаря! –

1

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

0

Существует одна проблема в коде, вы не можете определить свой метод как «частная пустота уведомит()», поскольку «уведомляет()» является метод, определенный в классе Object

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