Классы-утилиты для синхронизации потоков. — КиберПедия 

Эмиссия газов от очистных сооружений канализации: В последние годы внимание мирового сообщества сосредоточено на экологических проблемах...

Типы сооружений для обработки осадков: Септиками называются сооружения, в которых одновременно происходят осветление сточной жидкости...

Классы-утилиты для синхронизации потоков.

2022-10-10 52
Классы-утилиты для синхронизации потоков. 0.00 из 5.00 0 оценок
Заказать работу

Понятно, что мы говорили, что надо писать классы синхронизации. Но вопрос тут непростой – надо или не надо. В библиотеке не надо, а нам надо. Если каждый будет одно и то же писать, каждый без опыта и пытается в своих ошибках разобраться как это делать правильно. Понятно, что это для нас проблемный подход. И в версиях 1.5 – 1.6 – 1.8 они их все время по чуть-чуть добавляют. Можно в этом убедиться. Почему так происходит? Приходит много запросов и сталкиваясь с проблемами на Java пишите сразу в Oracle, а они пишут людям, и люди пишут. Надо писать, потому что, когда определенная статистика собирается, они говорят «смотри, а вот это нужно всем». И они это сделают. Так и должно быть. И поэтому вот то, что мы сейчас видим – это благодаря только тем, кто пишет. Нет, они конечно могут что-то сочинить, но жизнь ставит какие-то задачи, и мы можем попросить помочь нам стандартную задачу решить.

Кстати, на слайде появилось знакомое слово «семафор», но видите, он реализован в виде класса.

Semaphores: A semaphore is a counter that controls the access to one or more shared resources. This mechanism is one of the basic tools of concurrent programming and is provided by most of the programming languages. CountDownLatch: The CountDownLatch class is a mechanism provided by the Java language that allows a thread to wait for the finalization of multiple operations. CyclicBarrier: The CyclicBarrier class is another mechanism provided by the Java language that allows the synchronization of multiple threads in a common point. Phaser: The Phaser class is another mechanism provided by the Java language that controls the execution of concurrent tasks divided in phases. All the threads must finish one phase before they can continue with the next one. This is a new feature of the Java 7 API. Exchanger: The Exchanger class is another mechanism provided by the Java language that provides a point of data interchange between two threads.

Семафор:  вы создаете объект этого класса. Кстати он наследует от Object. И вы указываете количество разрешений, которые на какой-то ресурс вы выдаете. Например, к этому ресурсу вы разрешаете обращаться пятерым. И каждый, кто к этому ресурсу обращается, получает его с помощью вызова «Дай!», он уменьшает этот счетчик на 1. Ну и когда-то закончится и пятеро все исчерпают. И соответственно, следующий будет ждать. Т.е. семафор позволяет ограничить количество потоков, которые обращаются к какому-то ресурсу. А каждый кто, например, закончил работать, он обязан вызвать Release. И тогда счетчик опять увеличивается. И если вы как-то можете соблюдать баланс, то он будет все время работать, и никто не будет блокирован. В чем прелесть всех этих классов? Можно сделать так, что блокировки-то не будет.

Phaser: Она похожа на CyclicBarrier. Т.е. идея такая. Представьте, что у вас есть пять потоков, которые выполняют работу. У каждого потока каждая своя. НО! Работа состоит из этапов. Сделал-сделал-сделал. Допустим 3 этапа. Но в конце каждого этапа я хочу, чтобы они синхронизировались. Они делают все первый этап с разной скоростью. Дошли и ждут других. Потом второй этап. Кто первый – ждет. Все пришли, синхронизировались, т.е. они все закончили второй этап и пошли на третий. Вдруг они в этот момент где у них там синхронизация как-то данные должны объединить, может быть общую статистику посмотреть. Это ваша задача, но когда мы знаем, что все трое закончили, я могу спокойно с данными уже работать. И поэтому мне не придется писать свой навороченный код, который должен определять момент, когда все завершили. А если кто-то вперед убежал? У него же данные будут в другом состоянии, я не могу их убрать и пользоваться ими. он их на следующем этапе начнет снова менять. Поэтому как мне сделать это руками, если нужно посчитать какую-то общую статистику? Не нужно уже это руками делать. Вот, все что здесь люди просили.

Exchanger:

Это возможность создания точки, где потоки будут обмениваться данными. Зачем это может понадобиться? Какие-то алгоритмы, вычисления, но понимаете, если может быть разобраться в этом серьезно и это грамотно использовать, то я думаю, что применение такого класса сократить количество необходимых синхронизаций. Т.е. каждый пашет отдельно и не думает, что к его данным начнут обращаться. Есть точка синхронизации и точка взаимодействия. Всё. Вот там произойдет какое-то взаимодействие. Еще одна красивая реализация.

Сегодня мы посмотрим последнюю маленькую лабораторную №3. Но в начале мы должны разобраться, как была решена проблема на 15 слайде, которая называется «проверка доступности ресурса».

Вот что они сделали. Они сделали целую архитектуру из так называемых блокировок «locks». Внутри этих блокировок (классов, интерфейсов) конечно же спрятано synchronized, но функциональность synchronizedвы видели нулевая, кроме того, что он блокирует. А здесь сделано все по уму. Вот мы создали объект lock. Неважно какой именно объект. Главное, что на объекте, который реализует интерфейс lockвы можете вызвать метод lock. Тем самым, что вы говорите? Что мы блокируем ресурс. Кстати, то, что здесь написано lock, потом идет unlock – это идея. Но это неправильный код естественно, но он слишком простой. Давайте я покажу в документации. Это в отдельном даже пакете все лежит. util-->concurrent-->locks–целый пакет.

Есть интерфейс lock, а есть его реализация ReentrantLock. Ну наверно на него и нужно смотреть.

class X { private final ReentrantLock lock = new ReentrantLock(); //...   public void m() { lock.lock(); // block until condition holds try {   //... method body } finally {   lock.unlock() } }  }

 

А вот как им надо пользоваться. Это рыба (заготовка), но она правильная. Вот я хочу гарантировать, что кто-то кто будет работать с методом «m» только один поток на этом объекте (this) сможет зайти в этот метод. Да не вопрос. Создали объект lock. В этом методе «m»(для себя) написали lock.lock(). Всё. Кто первый поток пришел, вот в этом объекте lockбудет занято. Любой другой кто сюда придет, он в этот lockсюда упрется и соответственно «до свидания». Так как это не staticlock, то это будет в каждом объекте (в каждом this). Вот как мы монитор делали (очень похоже). У вас в каждом объекте свой специальный объект для блокировки. Ну по сути мы объект класса Xблокировали. Но в нашем случае просто synchronizedи вы ничего сделать не можете, а здесь вы видите функционал. Значит для того, чтобы эту блокировку снять (это не synchronizedкоторый сам все умеет) вы обязаны написать unlock в finally, иначе эта блокировка.

Здесь к сожалению примера кода нет. Но у вас в интерфейсеlockесть метод trylockсо временем. Я не просто пишу lock, а пишу а можно к этому ресурсу обратиться? если trylockмне говорит false, то я понимаю, что он уже занят и я разворачиваюсь и ухожу. А со временем? То же самое. Я говорю «ладно, подожду 5 секунд (не больше)». Я буду блокирован в вызове tryblockна 5 секунд. Если за 5 секунд статус не изменится, кто-то не вызовет unlock, то я развернусь и уйду. Это не капкан на неизвестно что. Поэтому хотя бы только ради такой возможности проверить доступность ресурсов, эти классы уже становятся крайне интересными.

Но и на базе этих простейших примитивов, которые мы сейчас видим ReentrantLock, можно создавать уже более сложную бизнес-логику. Более успешная бизнес-логика – это как раз есть вариант readLock(); и writeLock();

Это и есть тот самый паттерн «читатель» и «писатель». Понятно, что все начинается с одного объекта. Вы должны создать один объект (вон он в первой строчке), а потом из него попросить блокировку на чтение и блокировку на запись. И у вас будут методы, которые читают и методы, которые пишут. И вы в каждом методе будете использовать свою правильную версию блокировок. И что это обеспечивает? А вот представьте, у вас есть объект, внутри которого, допустим:

· приходит сюда поток и начинает читать данные.

· приходит сюда поток и начинает читать данные.

· приходит сюда поток и начинает читать данные.

· приходит сюда поток и начинает читать данные.

· приходит сюда поток и начинает читать данные.

Да хоть тысяча! Блокировка на чтение читатели в любом количестве пропускают. И они все одновременно будут читать. Производительность не страдает. Ну, конечно, как всегда появится один умник, которые собирается менять данные. Ему что скажут? А он попросит «Я хочу блокировку на запись - writeLock()!». Ему скажут «Жди!». Вот пока читатели все не покинут, а новых читателей, кстати, как только появилась блокировка на запись, новых читателей пускать уже никто не будет. Вот эти должны будут покинуть и уйти из этого объекта потихонечку. Новые кто придут, им скажут ждать (они будут накапливаться). Эти потихонечку все покинут объект. Всё. Читателей нету. Теперь мы говорим, можешь работать. Если тут написать еще кто желает на запись, эти только по одному. Они все по отдельности пройдут, отработают, а потом снова всех читателей толпой запустят.


Поделиться с друзьями:

Археология об основании Рима: Новые раскопки проясняют и такой острый дискуссионный вопрос, как дата самого возникновения Рима...

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

Организация стока поверхностных вод: Наибольшее количество влаги на земном шаре испаряется с поверхности морей и океанов (88‰)...

Кормораздатчик мобильный электрифицированный: схема и процесс работы устройства...



© cyberpedia.su 2017-2024 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!

0.016 с.