2013-10-12 4 views
2

я следующий код в потоке 1:Две нити, одновременно входящие в один ArrayList?

synchronized (queues.get(currentQueue)) {   //line 1 
    queues.get(currentQueue).add(networkEvent);  //line 2 
} 

и следующее в потоке 2:

synchronized (queues.get(currentQueue)) { 
    if (queues.get(currentQueue).size() > 10) { 
     currentQueue = 1; 
    } 
} 

Теперь мой вопрос: Переменная currentQueue в настоящее время имеет значение 0. Когда нить 2 изменяет значение currentQueue на 1, а поток 1 ожидает в строке 1 (из-за синхронизации), то поток 1 затем использует обновленное значение currentQueue в строке 2 после завершения потока 2 (это то, что я хочу).

+0

Вы меняете его в локальном масштабе. – arynaq

+0

Ваша синхронизация неисправна. Из вашего кода ключ для доступа к очереди (и у вас их много) кажется индексом currentQueue.Это то, что вы должны регулировать доступ (и, в конечном счете, синхронизацию), особенно когда он доступен в режимах чтения/записи. – ylabidi

+0

да, конечно, потому что поток два сначала получил блокировку и обработал данные, поэтому после разблокировки по потоку 2 и фиксации по потоку 1 он имеет модифицированные данные по потоку 2. –

ответ

2

Ответ на вопрос, что это зависит. Я предполагаю, что есть другой фрагмент кода, который увеличивает текущую переменную currentQueue. В этом случае блокировка происходит не в переменной 'currentQueue', и это не происходит в коллекции 'очередей', но скорее это происходит в одной из 10 очередей (или, как многие из вас есть) в очереди ''.

Следовательно, если оба потока имеют доступ к одной очереди (например, очередь 5), тогда ответ на ваш вопрос будет да. Тем не менее, для того, чтобы это произошло, это один из десяти шансов (один по шансу x, где x = число или очереди в «очередях»). Поэтому, если потоки обращаются к разным очередям, тогда ответ будет отрицательным.

+0

благодарит за вашу помощь – msc

2

Правильный ответ на ваш вопрос: результат не определен.

Объект вашего монитора - queues.get (currentQueue), но поскольку currentQueue является переменным, ваш монитор является переменным, поэтому состояние, в котором он сейчас находится, более или менее случайное. Эффективно этот код в конечном итоге сломается.

Простой способ исправить это будет функция, как это:

protected synchronized QueueType getCurrentQueue() { 
    return queues.get(currentQueue); 
} 

Однако это все еще плохой способ реализации целиком. Вы должны либо попытаться полностью исключить синхронизацию, используя параллельную очередь (например, ConcurrentLinkedQueue), либо работать с объектом блокировки/окончательного монитора.

final Object queueLock = new Object(); 
... 
synchronized(queueLock) { 
    queues.get(currentQueue).add(networkEvent); 
} 

Обратите внимание, что вы должны будете использовать, что замок каждый раз, когда вы получаете доступ queues или currentQueue и как определить набор данных, который вы используете.

+0

спасибо за помощь – msc

1

Предполагая, что у вас нет другой поток изменит значение currentQueue, да Thread 1 будет в конечном итоге с помощью очереди, на которую указывает обновленной стоимости currentQueue, так как вы вызываете queues.get (currentQueue) еще раз в теле синхронизированного блока. Это, однако, не означает, что ваша синхронизация звучит. Фактически вам нужно синхронизировать с currentQueue, поскольку он, как представляется, является общим ключом для доступа к текущей очереди.

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

+0

благодарит за вашу помощь – msc

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