Java Урок 48: ПОТОКИ, synchronized

Опубликовано: 23.08.2018

видео Java Урок 48: ПОТОКИ, synchronized

Java Урок 34 - Threads And Synchronization

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



Скачать исходники для статьи можно ниже

Ключом к синхронизации является концепция монитора. Монитор — это объект, который используется, как взаимоисключающая блокировка (mutually exclusive lock — mutex), или мьютекс.

Только один поток может в одно и то же время владеть монитором. Когда поток запрашивает блокировку, говорят, что он входит в монитор.


#Java Урок 22 Прерывание потока управления. Оператор break

Все другие потоки, которые пытаются войти в заблокированный монитор,

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

Обо всех прочих потоках говорят, что они ожидают монитора. Поток, который владеет монитором, может повторно войти в него, если пожелает.

Java для начинающих. Урок 47: Сериализация (часть 3). Transient, serialVersionUID.

Использование синхронизированных методов.

Синхронизация в Java проста, поскольку объекты имеют собственные, ассоциированные с ними неявные мониторы. Чтобы войти в монитор объекта, следует просто вызвать метод, модифицированный ключевым словом synchronized.

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

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

Следующая программа содержит три простых класса. Первый из них, Callme, имеет единственный метод — call().

Этот метод принимает параметр msg класса String и пытается вывести строку msg внутри квадратных скобок.

Интересно отметить, что после того, как метод call() выводит открывающую скобку и строку msg, он вызывает метод Thread.sleep(1000), который приостанавливает текущий поток на одну секунду.

Конструктор следующего класса, Caller, принимает ссылку на экземпляры

классов Callme и String, которые сохраняются соответственно в переменных target и msg.

Конструктор также создает новый поток, который вызовет метод

run() объекта. Поток стартует немедленно.

Метод run() класса Caller вызывает метод call() для экземпляра target класса Callme, передавая ему строку msg.

Наконец, класс Synch начинает с создания единственного экземпляра класса Callme и трех экземпляров класса Caller, каждый с уникальной строкой сообщения.

Один экземпляр класса Callme передается каждому конструктору Caller():

// Эта программа не синхронизирована, class Callme { void call(String msg) { System.out.print("[" + msg); try { Thread.sleep(1000); } catch(InterruptedException e) { System.out.println("Прервано"); } System.out.println("]"); } } class Caller implements Runnable { String msg; Callme target; Thread t; public Caller(Callme targ, String s) { target = targ; msg = s; t = new Thread(this); t. start(); } public void run() { target.call(msg); } } class Synch { public static void main(String args[]) { Callme target = new Callme(); Caller obi = new Caller(target, "Добро пожаловать"); Caller ob2 = new Caller(target, "в синхронизированный") Caller ob3 = new Caller(target, "мир!"); // ожидание завершения потока try { obi.t.j oin() ; ob2.t.join(); ob3.t.join(); } catch(InterruptedException e) { System.out.println("Прервано"); } } }

Вот вывод этой программы.

[Добро пожаловать[в синхронизированный[мир!] ] ]

Как видите, вызывая метод sleep(), метод call() позволяет переключиться на выполнение другого потока. Это приводит к смешанному выводу трех строк сообщений.

В этой программе нет ничего, что предотвращает вызов потоками одного

и того же метода в одном и том же объекте в одно и то же время.

Это называется состоянием гонок (race condition) или конфликтом, поскольку три потока соревнуются друг с другом в окончании выполнения метода.

Этот пример использует метод sleep(), чтобы сделать эффект повторяемым и наглядным.

В большинстве ситуаций этот эффект менее заметен и менее предсказуем, поскольку вы не можете предвидеть, когда произойдет переключение контекста. Это может привести к тому, что программа один раз отработает правильно, а другой раз — нет.

Чтобы исправить эту программу, следует cинхронизировать доступ к методу call(). То есть в одно и то же время вы должны разрешить доступ к этому методу только одному потоку. Чтобы сделать это, вам нужно просто предварить объявление метода call() ключевым словом synchronized, как показано ниже:

class Callme { synchronized void call(String msg) {

Это предотвратит доступ другим потокам к методу call(), когда один из них уже использует его. После того как слово synchronized добавлено к методу call(), результат работы программы будет выглядеть следующим образом: [Добро пожаловать] [в синхронизированный] [мир!]

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

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

Однако несинхронизированные методы экземпляра по-прежнему остаются доступными для вызова.

Хотя создание синхронизированных методов в ваших классах — простой и эффективный способ синхронизации, все же он работает не во всех случаях.

Чтобы понять почему, рассмотрим следующее.

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

Более того, класс был написан не вами, а независимым разработчиком, и у вас нет доступа к его исходному коду. Значит, вы не можете добавить слово synchronized к объявлению соответствующих методов класса.

Как может быть синхронизирован доступ к объектам такого класса? К счастью, существует довольно простое решение этой проблемы: вы просто заключаете вызовы методов этого класса в блок synchronized.

Вот общая форма оператора synchronized:

synchroni zed(объект) { // операторы, подлежащие синхронизации }

Здесь объект — это ссылка на синхронизируемый объект. Блок synchronized гарантирует, что вызов метода объекта произойдет только тогда, когда текущий поток успешно войдет в монитор объекта.

Ниже показана альтернативная версия предыдущего примера с использованием синхронизированного блока внутри метода run().

// Эта программа использует синхронизированный блок, class Callme { void call(String msg) { System.out.print("[" + msg); try { Thread.sleep(1000); } catch (InterruptedException e) { System.out.println("Interrupted"); } System.out.println("]"); } } class Caller implements Runnable { String msg; Callme target; Thread t; public Caller(Callme targ, String s) { target = targ; msg = s; t = new Thread(this); t.start(); } // синхронизированные вызовы call() public void run() { synchronized(target) { // синхронизированный блок target.call(msg); } } } class Synch1 { public static void main(String args[]) { Callme target = new Callme(); Caller obi = new Caller(target, "Добро пожаловать"); Caller ob2 = new Caller(target, "в синхронизированный"); Caller ob3 = new Caller(target, "мир!"); // ожидание завершения потока try { obi.t.join(); ob2.t.join(); ob3.t.join(); } catch(InterruptedException e) { System.out.println("Прервано"); } } }

Здесь метод call() не модифицирован словом synchronized. Вместо этого

используется оператор synchronized внутри метода run() класса Caller. Это позволяет получить тот же корректный результат, что и в предыдущем примере, поскольку каждый поток ожидает окончания выполнения своего предшественника.

Новости

Видео рок с женским вокалом
Опубликовано: 10.09.2017 Рок ДИВЫ, которых ты не знал Nightwish — финская метал-группа, исполняющая песни преимущественно на английском языке. Была образована Туомасом Холопайненом в 1996 году в городе

Видео транс вокал радио
Опубликовано: 09.07.2017 [Trance] Female Vocal Trance (June 2017) #125 Если хочется в полной мере насладиться ощущением полета, раскрыться навстречу свежим впечатлениям и окунуться в бездонный океан

Уроки вокала для взрослых
Опубликовано: 30.08.2018 УРОКИ ВОКАЛА ДЛЯ ВЗРОСЛЫХ №2 (ПОСТАНОВКА ГОЛОСА, КАК НАУЧИТЬСЯ КРАСИВО ПЕТЬ) Школа пения в Москве «Петь легко» обучит Вас всем базовым навыкам пения и поможет раскрыть Ваши

Как заработать вокалисту на новый год
Опубликовано: 30.08.2018 Кaк oднa фрaзa пoменялa мoю жизнь? [Автoр - Егoр Щербинa] Новогодние праздники уже на носу. Кто-то спешит потратить заработанные честным трудом денежки на развлечения и подарки,

Вирус «вокальной посредственности»
Когда мы только начинаем чем-то заниматься, мы стремимся стать таким же, как те, кто долго занимается этим делом. А первые успехи провоцируют стать лучше всех. И это нормальное развитие событий. Но, бывают

Методика постановки голоса в студии эстрадного вокала
На сегодняшний день в значение «вокального искусства» вкладывается гораздо больше, чем это было несколько лет назад. Теперь недостаточно иметь просто красивый голос и действительно уметь петь. С современными

Бэк-вокал - Мои статьи - Интересно почитать - A-Kittens
Что такое бэк-вокал («Backing vocal»)? Перевести эту фразу с английского языка можно примерно так – «Поддерживающий вокал», а в несколько другой смысловой вариации – «Прикрывающий вокал». Что же…

Уроки Гроулинга/скриминга/пиглета(экстрим-вокал)
Надеюсь,малята, буду сюда выписывать свои и не свои статьи о том какправильно орать(одинчувак выпустил ДВД по этому и заработал кучу бабок,но я чувак некоммерческий и подарю вам это исскуство бесплатно)...

Мифы о вокале
Опубликовано: 01.09.2018 Мифы o вoкaле: Чтo есть и пить, чтoбы петь? Недавно одна моя ученица спросила: «А что, мой головной голос реально идет из головы?».  И я решила сделать подборку мифов о

Уроки вокала. Штробас - как расслабление и основа Хрипа
Сегодня вы узнает прием, который помогает разогревать и расслаблять связки. А также благодаря этому приему я научилась петь с хрипом. Этот прием называется штробас. Штробас использовали давным-давно

rss