2013-08-26 4 views
4

У меня есть очень простой вопрос о SynchronizedList.synchronizedList доступ несколькими потоками

Допустим, у меня есть synchronizedList, как -

List syncList = Collections.synchronizedList(new ArrayList<>()) 

Теперь мой сценарий Thread А пытается получить доступ к add() апи и темы B пытается получить доступ к remove() апи из synchronizedList. Будет ли оба потока иметь доступ к обеим (добавить и удалить) api в одно и то же время.

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

+2

Вы правы. Существует один замок, и не имеет значения, какой метод вы вызываете, это объект, который заблокирован, а не метод. –

ответ

1

Можете ли вы уточнить, что вы имеете в виду под «в то же время»?

Синхронизированная структура данных заставит один из двух потоков ждать, пока другой не завершит свою работу. «Ожидание блокировки» может быть принудительно применено на разных уровнях детализации и может разрешать чтение при синхронизации записи (в том числе удалений), но принцип остается неизменным.

+0

В частности, 'synchronizedList' предотвратит повреждение структуры данных« Список », но не будет препятствовать условиям гонки чтения-обновления-записи. – chrylis

0

я бы решить проблему таким образом:

Сначала я создать класс список обертку, как это:

public class MySyncList{ 
    private List<String> myList; 
    public MySyncList(){ 
     this.myList = new ArrayList<String>(); 
    } 
    public synchronized void add(String elem){ 
     this.myList.add(elem); 
    } 
    public synchronized void remove(String elem){ 
     this.myList.remove(remove); 
    } 
    public synchronized List<String> getList(){ 
     return this.myList; 
    } 
} 

чем доступ из нитей:

final MySyncList list = new MySyncList(); // final so other threads can access it 

ExecutorService service = Executors.newFixedThreadPool(10); 
for(int i=0;i<20;i++){ 
    service.execute(new Runnable(){ 
     public void run(){ 
     list.add("something"); 
     list.remove("something"); 
     } 
    }); 
} 
service.shutDown(); 
while(!service.isTerminated()); 
List<String> finalList = list.getList(); 
+3

Huh ... Какой смысл переписывать 'Collections.synchronizedList'? – assylias

6

Воле Оба потока могут получить доступ к Оба (добавить и удалить) api в в то же время.

Ответ отрицательный.

Если вы получаете шанс посмотреть на Collections.synchronizedList(List) исходном коде, вы видите, что метод создание экземпляра статического внутреннего класса с именем SynchronizedList или SynchronizedRandomAccessList, в зависимости от типа List отправленных в качестве аргумента.

Теперь оба этот статический внутренний класс расширить общий класс, называемый SynchronizedCollection, который поддерживает mutex объекта, на котором все операции методы синхронизации на

Этого mutex объекта присваиваются this, который по существу означает, что в mutex объекте это тот же возвращенный экземпляр.

Поскольку методы add() и remove() выполняются под блоком с

synchronized(mutex) { 

} 

, A поток который выполняет add (и aquires замок на mutex), не позволит другой поток выполнить remove (по люксовый замок на том же mutex), так как у прежнего уже заблокированmutex.последней нить будет ждать до замка, полученного бывшей нити на mutex получает выпущенный.

Так что, да add() и remove() являются взаимоисключающие

-1

Это правильно, синхронизированный список полностью поточно. Таким образом, с точки зрения атомарности потоки не смогут получить доступ к списку одновременно. Доступ из разных потоков будет происходить последовательно.

+1

Это не полностью потокобезопасно, потому что итератор этого списка не является потокобезопасным. –

+0

Вопрос был, есть ли список threadsafe? Да, в самом деле! Итератор НЕ является частью списка. Сам синхронизированный список и его внутренняя структура полностью потокобезопасны. –

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