Проблема синхронизации Java - чат нескольких приложений чата - PullRequest
0 голосов
/ 02 сентября 2011

Я занимаюсь разработкой приложения для чата. У меня есть функция, которая обрабатывает сообщения чата. Каждый чат-номер идентифицируется уникальным шорткодом . Теперь я хочу, чтобы при обработке сообщения для одного короткого кода ожидалось другое сообщение с таким же коротким кодом, а сообщения для других коротких кодов должны продолжаться.

Пожалуйста, примите во внимание следующий код, в чем проблема, поскольку сообщения для одного и того же шорткода обрабатываются параллельно. Я просто не могу догадаться, проблема

private HashMap<String, Object> locks = new HashMap<String, Object>();

public void handleShortCode(String shortcode,String message,String from)
{
    Object lock = null;

    lock = locks.get(shortcode);
    if (lock == null)
    {
        locks.put(shortcode, lock = new Object());
    }

    synchronized (lock)
    {
        System.out.println("Handling shortcode:" + shortcode);
        // processing
        System.out.println("Successfully handled shortcode:" + shortcode + " ......");
    }
}

Ответы [ 2 ]

4 голосов
/ 02 сентября 2011

Первая причина, которую я вижу, здесь

Object lock = null;

lock = locks.get(shortcode);
if (lock == null)
{
    locks.put(shortcode, lock = new Object());
}

Этот блок кода выполняется вне любого мьютекса, поэтому несколько потоков могут запускать его одновременно, поэтому каждый из потоков (имеющих одинаковый шорткод) получил свою собственную блокировку , независимую друг от друга (и только один из них будет храниться в hashmap блокировок - о чем и идет речь, поскольку обычный HashMap не предназначен для одновременного использования - вы не можете предсказать, какой именно «put» будет действительно действовать, в каком порядке, вы даже можете получить исключение или неправильное поведение в этом коде, если текущая позиция вызывает изменение размера, например). Поскольку каждый поток получает свою собственную блокировку, он не препятствует захвату его одновременно с другими потоками, получая другую блокировку.

Самый простой (но не очень эффективный) способ исправить это:

private HashMap<String, Object> locks = new HashMap<String, Object>();
private final Object hashmapLock = new Object();
public void handleShortCode(String shortcode,String message,String from)
{
    Object lock = null;
    synchronized(hashmapLock){
      lock = locks.get(shortcode);
      if (lock == null)
      {
          locks.put(shortcode, lock = new Object());
      }
    }
    synchronized (lock)
    {
        System.out.println("Handling shortcode:" + shortcode);
        // processing
        System.out.println("Successfully handled shortcode:" + shortcode + " ......");
    }
}

Таким образом, вы получаете ровно одну блокировку для каждого шорткода. Более эффективный способ - использовать что-то вроде ComputableConcurrentHashMap из библиотеки Guava.

1 голос
/ 02 сентября 2011

С синхронизированным механизмом все в порядке, но, возможно, вы захотите взглянуть на интерфейс блокировки в пакете java.util.concurrent.locks. Они более многословны в использовании, но допускают большую гибкость, поскольку можно делать такие вещи, как попытка неудачи или попытка получить данные с таймаутом.

...