Главная » Java » Синхронизированные оболочки коллекций

0

 

  Все реализации коллекций, объявленные в пакете java.util, сами по себе не поддерживают средств синхронизации (за исключением коллекций некоторых устаревших типов, рассмотренных в разделе 16.12). Ответственность за обеспечение синхронизации доступа к содержимому коллекции со стороны нескольких потоков вычислений обычно возлагается на прикладной код. Автор кода может добиться такой цели, явно обозначая методы или выражения признаком synchronized либо проектируя код в расчете на возможность обращения к коллекции только из одного потока вычислений. Подобные приемы как раз и отвечают ситуациям, в которых коллекции применяются наиболее час-то — объекты коллекций, как правило, создаются в виде локальных переменных в теле методов либо объявляются в форме private-полей классов с синхронизированным кодом.

     Помимо названных подходов, существует возможность использования коллекций

в контексте синхронизированных оболочек (synchronized wrappers). Объект синхро-

изированной оболочки активизирует методы "внутренней" коллекции только после

выполнения необходимых действий по синхронизации доступа к ее содержимому,

чтобы получить объект синхронизированной оболочки, следует передать ссылку на

объект    коллекции    одному    из    статических    методов    класса    Collections:

synchronizedCol lection,             synchronizedset,            synchronizedSortedSet, synchronizedList, synchronizedMap или synchronizedSortedMap. Каждый из перечисленных методов возвращает объект оболочки коллекции соответствующего типа, методы которого полностью синхронизированы, что гарантирует безопасность их использования в многопоточной среде. Ниже приведен фрагмент кода, обеспечивающий создание нового объекта HashMap, который вполне готов к единовременному изменению его содержимого несколькими потоками вычислений.

Map unsyncMap = new HashMap( );   // Несинхронизированная версия

Map syncMap = Collection.synchronizedMap(unsyncMap);

 

  Объект коллекции, адресуемый переменной unsyncMap, относится к полноценной реализации интерфейса Map, которая, однако, не поддерживает механизм синхронизации. Объект Map, возвращаемый методом Collections, synch ronizedMap, поддерживает синхронизированные варианты всех методов Map, вызовы которых, в свою очередь, передаются объекту "внутренней" коллекции unsyncMap. Изменение содержимого коллекции, которая на самом деле существует в единственном экземпляре, может быть выполнено при посредничестве любого из двух объектов — "внутреннего" несинхронизированного, unsyncMap, либо "внешнего" синхронизированного, syncMap.

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

 

// Добавить много элементов,   но захватить блокировку

 // только один раз

synchronized  (syncMap)  {

for  (int i  =0;   i  < keys.length;   i++)

 unsyncMap.put(keys[i],   values[i]);

}

   Итераторы, возвращаемые объектами синхронизированных оболочек колле ций, синхронизированными не являются, но при необходимости их можно сд лать таковыми, если применить следующий подход:

synchronized  (syncMap)   {

System.out.println("Содержимое  коллекции:");

Iterator  it = syncMap. keySet( ).iterator() ;

                while  (it.hasNext( ))   {

               object key = it.next( )

        System.out.println(key +”:”+ syncMap.get(key));

   }

}

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

 

Источник: Арнолд, Кен, Гослинг, Джеймс, Холмс, Дэвид. Язык программирования Java. 3-е изд .. : Пер. с англ. – М. : Издательский дом «Вильяме», 2001. – 624 с. : ил. – Парал. тит. англ.

По теме:

  • Комментарии