2013-04-13 5 views
1

Например,Как локально синхронизировать две карты?

class Test{ 
    static Map a = new ... 
    static Map b = new ... 

    public void process(){ 

     ... 
     a.put(...); 
     b.put(...); 
    } 
} 

ли я заблокировать, как это:

synchronized(a){ 
    a.put(); 
} 

synchronized(b){ 
    b.put(b); 
} 

Это кажется неуклюжим. Любой другой правильный способ сделать это? Благодарю.

+1

Это действительно зависит от того, какие гарантии параллельности вы хотите иметь. –

+0

Для этого вы можете использовать 'Lock', что может быть чрезмерным или одним синхронизированным методом. –

ответ

2

Нет, вам нужны обе операции в одном блоке synchronized, иначе другой поток может видеть несоответствия между двумя картами.

Один из возможных вариантов будет использовать метод synchronized, или вы можете использовать какой-либо другой частный объект или одну из карт в качестве монитора. Вот синхронизированное пример метода:

static Map a = new ... 
    static Map b = new ... 

    public synchronized void process(){ 

     ... 
     a.put(...); 
     b.put(...); 
    } 
} 
0

Вам нужно запустить обе операции в пределах одного synchronized блока. Стоит отметить, что в вашем примере вы определили карты статически, а метод process() - это метод экземпляра. Синхронизация метода будет означать, что вызовы на этот экземпляр будут синхронизированы, но вызовы для двух разных экземпляров не будут (поскольку блокировка, используемая при применении ключевого слова synchronized для метода, фактически равна this). Вы можете либо сделать метод process() статическим, либо использовать блок synchronized(Test.class) {}, чтобы убедиться, что нет гонок.

Вам также нужно быть осторожным в том, как вы показываете карты клиентам - если вы предлагаете их как свойства, то я бы, вероятно, обернул их Collections.unmodifiableMap(), чтобы гарантировать, что больше ничего не может пойти и винт с ними, пока вы не смотрите - однако это не полностью защищает от клиентов, имеющих «странное» время, поскольку они все еще видят, что изменения происходят в потенциально опасном режиме. Таким образом, я бы, вероятно, также объявлять типы, как ConcurrentHashMap, чтобы сделать вещи немного безопаснее (хотя есть еще некоторые опасные операции, такие как обмен итератора между потоками)

1

Вы можете использовать выделенный объект как

Object mapLock = new Object(); 

для синхронизации.

Или вы можете синхронизировать с a, имея в виду, что даже если вам нужен доступ к b, вам необходимо синхронизировать его с a.

Синхронизация по this не является хорошей идеей в целом. Я имею в виду, что это плохая привычка, и это может привести к плохой производительности или неочевидным взаимоблокировкам, если не в этом, а в других приложениях, которые вы делаете.

Avoid synchronized(this) in Java?

Вы можете также рассмотреть возможность использования ReadWriteLock из пакета параллелизма.

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