Synchronized java что это

Ключевое слово synchronized в Java

Synchronized java что это. facebook. Synchronized java что это фото. Synchronized java что это-facebook. картинка Synchronized java что это. картинка facebookSynchronized java что это. twitter. Synchronized java что это фото. Synchronized java что это-twitter. картинка Synchronized java что это. картинка twitterSynchronized java что это. tumblr. Synchronized java что это фото. Synchronized java что это-tumblr. картинка Synchronized java что это. картинка tumblrSynchronized java что это. facebook. Synchronized java что это фото. Synchronized java что это-facebook. картинка Synchronized java что это. картинка facebookSynchronized java что это. twitter. Synchronized java что это фото. Synchronized java что это-twitter. картинка Synchronized java что это. картинка twitterSynchronized java что это. tumblr. Synchronized java что это фото. Synchronized java что это-tumblr. картинка Synchronized java что это. картинка tumblr

Synchronized java что это. synchronized v java. Synchronized java что это фото. Synchronized java что это-synchronized v java. картинка Synchronized java что это. картинка synchronized v java

Привет! В этой статье мы расскажем про ключевое слово synchronized.

Что такое synchronized

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

Synchronized java что это. 1 1. Synchronized java что это фото. Synchronized java что это-1 1. картинка Synchronized java что это. картинка 1 1

Каждый из них занимается своими делами.

Synchronized java что это. 2. Synchronized java что это фото. Synchronized java что это-2. картинка Synchronized java что это. картинка 2

Потом им обоим понадобились одни и те же данные, которые спрятаны за дверью:

Synchronized java что это. 3. Synchronized java что это фото. Synchronized java что это-3. картинка Synchronized java что это. картинка 3

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

Synchronized java что это. 4. Synchronized java что это фото. Synchronized java что это-4. картинка Synchronized java что это. картинка 4

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

Synchronized java что это. you shall not pass. Synchronized java что это фото. Synchronized java что это-you shall not pass. картинка Synchronized java что это. картинка you shall not pass

Synchronized java что это. 5. Synchronized java что это фото. Synchronized java что это-5. картинка Synchronized java что это. картинка 5

Synchronized java что это. 6. Synchronized java что это фото. Synchronized java что это-6. картинка Synchronized java что это. картинка 6

Пример

Для блока кода

Synchronized java что это. 7. Synchronized java что это фото. Synchronized java что это-7. картинка Synchronized java что это. картинка 7

В коде это может выглядеть так:

Для метода

Стоит заметить, что данный synchronized метод можно воспринимать так:

Если бы он был статическим, то представление слегка поменялось бы на:

Думаю, Вы заметили, что поменялись «ключи» синхронизации.
«Живые» примеры использования synchronized можно найти, например, в статье про реализации патерна программирования Singleton.

Стоит знать

Если Вы будете еще что-то читать про synchronized, Вы можете встретить такие термины:

В чем же минус synchronized

Надеемся, что наша статья была Вам полезна. Можно записаться к нам на курсы по Java на сайте.

Источник

BestProg

Синхронизация. Монитор. Общие понятия. Ключевое слово synchronized

Содержание

Поиск на других ресурсах:

1. Понятие синхронизации между потоками. Необходимость применения синхронизации. Монитор

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

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

Синхронизация базируется на использовании мониторов. Монитор — это объект, который используется для взаимоисключающей блокировки. Взаимоисключающая блокировка позволяет владеть монитором только одному объекту-потоку. Каждый объект-поток имеет собственный, неявно связанный с ним, монитор.

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

Монитором может обладать только один поток. Если поток (объект) обладает монитором, то он при необходимости может повторно войти в него.

В языке Java синхронизация применяется к целым методам или фрагментам кода. Исходя из этого существует два способа синхронизации программного кода:

Модификатор доступа synchronized применяется при объявлении синхронизированного метода и имеет следующую общую форму:

3. Оператор synchronized() < >. Общая форма

Общая форма оператора synchronized () следующая:

4. Пример, демонстрирующий синхронизированный доступ к общему методу из трех разных потоков. Применение модификатора доступа synchronized

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

Результат выполнения программы

Если в вышеприведенном примере перед методом Get() класса Array5 убрать ключевое слово synchronized

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

5. Пример использования оператора synchronized() <> для синхронизированного доступа к общему ресурсу

После внесенных изменений, сокращенный код программы будет следующий:

Источник

5 вещей, которых вы не знали о многопоточности

Хоть от многопоточности и библиотек, которые её поддерживают, отказываются немногие Java-программисты, но тех, кто нашёл время изучить вопрос в глубину ещё меньше. Вместо этого мы узнаём о потоках только столько, сколько нам требуется для конкретной задачи, добавляя новые приёмы в свой инструментарий лишь тогда, когда это необходимо. Так можно создавать и запускать достойные приложения, но можно делать и лучше. Понимание особенностей компилятора и виртуальной машины Java поможет вам писать более эффективный, производительный код.

В этом выпуске серии «5 вещей …», я представлю некоторые из тонких аспектов многопоточного программирования, в том числе synchronized-методы, volatile переменные и атомарные классы. Речь пойдет в особенности о том, как некоторые из этих конструкций взаимодействуют с JVM и Java-компилятором, и как различные взаимодействия могут повлиять на производительность приложений.

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

1. Synchronized-метод или synchronized-блок?

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

Когда JVM выполняет synchronized-метод, выполняющийся поток определяет, что в method_info этого метода проставлен флаг ACC_SYNCHRONIZED. Тогда он автоматически устанавливает блокировку на объект, вызывает метод и снимает блокировку. Если вылетает исключение, поток автоматически снимает блокировку.
С другой стороны, synchronized-блок обходит встроенную в JVM поддержку запросов блокировок объекта и обработку исключений, так что это необходимо описывать явно в байт-коде. Если вы посмотрите на байт-код для блока, увидите в нём кучу дополнительных операций в сравнении с методом. Листинг 1 показывает вызов и того, и другого.

Листинг 1. Два подхода к синхронизации.

package com.geekcap ;
public class SynchronizationExample <
private int i ;

public synchronized int synchronizedMethodGet ( ) <
return i ;
>

public int synchronizedBlockGet ( ) <
synchronized ( this ) <
return i ;
>
>
>

Метод synchronizedMethodGet() method генерирует следующий байт-код:

А вот байт-код для метода synchronizedBlockGet():

Создание synchronized-блока выдало 16 строк байт-кода, тогда как synchronized-метода – только 5.

2. «Внутрипоточные» (ThreadLocal) переменные.

Если вы хотите сохранить один экземпляр переменной для всех экземпляров класса, вы используете статические переменные класса. Если вы хотите сохранить экземпляр переменной для каждого потока, используйте внутрипоточные (ThreadLocal) переменные. ThreadLocal переменные отличаются от обычных переменных тем, что у каждого потока свой собственный, индивидуально инициализируемый экземпляр переменной, доступ к которой он получает через методы get() или set().

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

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

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

3. Volatile переменные.

По моим оценкам, лишь половина всех разработчиков Java знает, что в Java есть ключевое слово volatile. Из них лишь около 10 процентов знают, что оно значит, и еще меньше знают, как эффективно его использовать. Короче говоря, определение переменной с ключевым словом volatile(«изменчивый») означает, что значение переменной будет изменяться разными потоками. Чтобы полностью понять, что значит volatile, во-первых, нужно понять, как потоки оперируют с обычными, не-volatile, переменными.

В целях повышения эффективности работы, спецификации языка Java позволяет JRE сохранять локальную копию переменной в каждом потоке, который ссылается на нее. Можно считать эти «внутрипоточные» копии переменных похожими на кэш, помогающий избежать проверки главной памяти каждый раз, когда требуется доступ к значению переменной.

Но представьте, что произойдёт в следующем случае: запустятся два потока, и первый прочитает переменную А как 5, тогда как второй – как 10. Если переменная А изменились от 5 до 10, то первый поток не будет знать об изменении, так что будет иметь неправильное значение А. Однако если переменная А будет помечена как volatile, то то в любое время, когда поток обращается к её значению, он будет получать копию А и считывать её текущее значение.

Если переменные в вашем приложении не меняются, то внутрипоточный кэш имеет смысл. В противном случае, очень полезно знать, что может сделать для вас ключевое слово volatile.

4. Volatile против synchronized.

int temp = 0 ;
synchronize ( myVolatileVar ) <
temp = myVolatileVar ;
>

synchronize ( myVolatileVar ) <
myVolatileVar = temp ;
>

Другими словами, если volatile переменная обновляется неявно, то есть значение читается, измененяется, а затем присваивается как новое, результат будет не-потокобезопасным между двумя синхронными операциями. Вы можете выбирать, следует ли использовать синхронизацию или рассчитывать на поддержку JRE автоматической синхронизации volatile переменных. Наилучший подход зависит от вашего случая: если присвоенное значение volatile переменной зависит от её текущего значения (например, во время операции инкремента), то нужно использовать синхронизацию, если вы хотите, чтобы операция была потокобезопасной.

5. Обновления атомарных полей.

Когда вам требуется примитивный тип, выполняющий операции инкремента и декремента, гораздо лучше выбрать его среди новых атомарных классов в пакете java.util.concurrent.atomic, чем писать synchronized блок самому. Атомарные классы гарантируют, что определённые операции будут выполняться потокобезопасно, например операции инкремента и декремента, обновления и добавления(add) значения. Список атомных классов включает AtomicInteger, AtomicBoolean, AtomicLong, AtomicIntegerArray, и так далее.

Своеобразным вызовом программисту в использовании атомарных классов является то, что все операции класса, включая get, set и семейство операций get-set тоже атомарные. Это значит, что операции чтения и записи, которые не изменяют значения атомарной переменной, синхронизированы, а не только важные операции чтения-обновления-записи. Если вы хотите более детального контроля над развертыванием синхронизированного кода, то обходной путь заключается в использовании атомарного апдейтера поля.

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

Атомарные апдейтеры типа AtomicIntegerFieldUpdater, AtomicLongFieldUpdater, и AtomicReferenceFieldUpdater по существу оболочки применяющиеся к volatile полям. Внутри, библиотеки классов Java используют их. Хотя они не часто используются в коде приложений, но у вас нет причин не начать облегчать свою жизнь с их помощью.

Листинг 2 демонстрирует пример класса, который использует атомарные обновления для изменения книги, которую кто-то читает:
Листинг 2. Класс Book.

public class Book
<
private String name ;

public String getName ( )
<
return name ;
>

Класс Book – просто POJO (plain old Java object – незамысловатый старый Java объект), у которого есть только одно поле: name.

Листинг 3. Класс MyObject.

/**
*
* @author shaines
*/
public class MyObject
<
private volatile Book whatImReading ;

public Book getWhatImReading ( )
<
return whatImReading ;
>

Класс MyObject в листинге 3 представляет, как и можно было ожидать, get и set методы, но метод set делает кое-что иное. Вместо того, чтобы просто предоставить свою внутреннюю ссылку на указанную книгу (что было бы выполнено закомментированным кодом в листинге 3), он использует AtomicReferenceFieldUpdater.

AtomicReferenceFieldUpdater

Javadoc определяет AtomicReferenceFieldUpdater так:

A reflection-based utility that enables atomic updates to designated volatile reference fields of designated classes. This class is designed for use in atomic data structures in which several reference fields of the same node are independently subject to atomic updates.
(Основанная на отражении утилита, которая разрешает атомарные обновления назначенным volatile ссылочным полям назначенных классов. Этот класс предназначен для использования в атомарных структурах данных, в которых несколько ссылочных полей одной и той же записи являются независимыми субъектами для атомарных обновлений)убейте меня, я не знаю, как это нормально перевести

В листинге 3 AtomicReferenceFieldUpdater создан через вызов метода newUpdater, который принимает три параметра.
• класс объекта, содержащего поле (в данном случае, MyObject)
• класс объекта, который будет обновляться атомарно (в данном случае, Book)
• имя поля для атомарного обновления

Значимым здесь является то, что метод getWhatImReading выполняется без синхронизации любого рода, в то время как setWhatImReading выполняется как атомарная операция.

В листинге 4 показано, как использовать setWhatImReading () и доказывается, что переменная изменяется правильно:

Листинг 4. Тест-кейс атомарного апдейтера.

import org.junit.Assert ;
import org.junit.Before ;
import org.junit.Test ;

public class AtomicExampleTest
<
private MyObject obj ;

@Before
public void setUp ( )
<
obj = new MyObject ( ) ;
obj. setWhatImReading ( new Book ( «Java 2 From Scratch» ) ) ;
>

Источник

Синхронизация потоков в Java

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

Зачем использовать синхронизацию в Java?

Если вы начинаете, по крайней мере, с двумя потоками внутри программы, существует вероятность того, что несколько потоков попытаются добраться до одного и того же ресурса. Это может даже создать неожиданный результат из-за проблем параллелизма.

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

Синхронизированные блоки в Java помечаются ключевым словом Synchronized. Этот блок в Java синхронизируется на некотором объекте. Все блоки, которые синхронизируются на одном и том же объекте, могут иметь одновременно только один поток, выполняющийся внутри них.

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

Типы синхронизации

Существует в основном два типа синхронизации.

Реализация блокировки

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

Начиная с Java 5, пакет java.util.concurrent.locks содержит много реализаций блокировки.

Вот как выглядит блокировка:

Метод lock() блокирует экземпляр Lock, так что все потоки, вызывающие lock(), блокируются до тех пор, пока не будет выполнена unlock().

Многопоточность без синхронизации

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

Вышеуказанные результаты программы:

Synchronized java что это. 1 output synchronization in java edureka. Synchronized java что это фото. Synchronized java что это-1 output synchronization in java edureka. картинка Synchronized java что это. картинка 1 output synchronization in java edureka

Многопоточность с синхронизацией

Это тот же пример, что и выше, но он печатает значение счетчика в последовательности. Каждый раз, когда мы запускаем его, он дает один и тот же результат.

Результат изображен ниже:

Synchronized java что это. output1 synchronization in java edureka. Synchronized java что это фото. Synchronized java что это-output1 synchronization in java edureka. картинка Synchronized java что это. картинка output1 synchronization in java edureka

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

Синхронизированное ключевое слово может использоваться с:

Synchronized: блок кода

Общий синтаксис для записи синхронизированного блока:

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

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

synchronized : метод

Общий синтаксис написания синхронизированного метода:

Здесь lockObject – это просто ссылка на объект, чья блокировка связана с монитором, который представляет синхронизированные операторы.

Подобно синхронизированному блоку, поток должен получить блокировку на подключенном объекте монитора с помощью синхронизированного метода. В случае синхронизированного метода объект блокировки:

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

Источник

Синхронизация в Java. Часть 1

Synchronized java что это. 2*a769TWQ4NJdHJc7tpd tPw. Synchronized java что это фото. Synchronized java что это-2*a769TWQ4NJdHJc7tpd tPw. картинка Synchronized java что это. картинка 2*a769TWQ4NJdHJc7tpd tPw

Jul 9, 2020 · 6 min read

Synchronized java что это. 1*Q9gCM9LKq8Yi9MdnZCRJuw. Synchronized java что это фото. Synchronized java что это-1*Q9gCM9LKq8Yi9MdnZCRJuw. картинка Synchronized java что это. картинка 1*Q9gCM9LKq8Yi9MdnZCRJuw

Прежде чем перейти к самой синхронизации, я объясню многопоточность на примере простого кода.

Synchronized java что это. . Synchronized java что это фото. Synchronized java что это-. картинка Synchronized java что это. картинка

Первым классом будет класс “Countdown”, а класс “ThreadColor” будет выглядеть вот так:

Synchronized java что это. 0*VHBSrsiQ9uR5Imnc. Synchronized java что это фото. Synchronized java что это-0*VHBSrsiQ9uR5Imnc. картинка Synchronized java что это. картинка 0*VHBSrsiQ9uR5Imnc

Здесь я создал второй класс, расширяющий Thread:

Synchronized java что это. . Synchronized java что это фото. Synchronized java что это-. картинка Synchronized java что это. картинка

Переходим к методу main, так как мы создали два класса, а затем запустили два потока из инструкции switch (рисунок 1), которая состоит из первого потока “Thread 1”, выводящего голубой текст, и второго потока “Thread 2”, выводящего фиолетовый текст.

Теперь давайте посмотрим, что происходит.

Synchronized java что это. 0*oD imT3LG8UP5z2J. Synchronized java что это фото. Synchronized java что это-0*oD imT3LG8UP5z2J. картинка Synchronized java что это. картинка 0*oD imT3LG8UP5z2J

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

А те п ерь мы добавим переменную экземпляра “ Private int I;”, которая заменит локальную переменную “ I”. Взглянем на результат:

Synchronized java что это. 0*8 NkMXfrmbuZZcpv. Synchronized java что это фото. Synchronized java что это-0*8 NkMXfrmbuZZcpv. картинка Synchronized java что это. картинка 0*8 NkMXfrmbuZZcpv

Теперь он получился совсем иным. Вместо последовательного выполнения каждым потоком отсчёта от 10 до 1, мы видим, что некоторые числа повторяются.

Почему?
Очевидно, что повторяется число 10, а также несколько других. Единственное же, что мы сделали, — это поменяли локальную переменную на переменную экземпляра:

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

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

Поэтому, когда несколько потоков работают совместно над одним объектом, они используют этот объект вместе. В этом случае если один поток изменяет значение, другой поток использует это изменённое значение. Аналогичным образом, когда “i” выступала в роли локальной переменной, потоки имели свои собственные версии этой переменной, но как только мы сделали “i” переменной экземпляра, два потока стали обращаться к этому общему ресурсу, хранящемуся в куче, поэтому каждый поток и пропускал некоторые числа.

Цикл for
Он уменьшает I на 1 и проверяет условие i>0. Суть цикла for заключается в выполнении нескольких шагов, а именно уменьшения, проверки и т.д. Отсюда получается, что поток может быть приостановлен между этими шагами. Он может быть приостановлен после уменьшения “i”, перед проверкой состояния или же сразу после выполнения всего кода и вывода результата в консоль. Уменьшение “i”, проверка условия и вывод в консоль значений: эти три шага могут послужить причиной остановки текущего потока.

Как можно догадаться, в первой попытке оба потока рассматривали значение “i” как 10, поэтому Thread 1 вывел 9, но Thread 2 вывел 8. Почему?

В то время как Thread 1 выполнял цикл for, Thread 2 должно быть его опередил, получил значение “i” в виде 9, выполнил блок for и вывел 8.

При обращении к общим ресурсам, мы вынуждены пройти через эту ситуацию, которая называется “ Thread interference” (коллизия потоков) или “ Race condition” (состояние гонки). Помните, что всегда возникает серьёзная проблема, когда дело доходит до написания или обновления общего ресурса.

Мы можем сделать это без пропуска чисел или избежания коллизии, т.е. передать один и тот же объект Countdown обоим потокам.

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

Synchronized java что это. 0*8zsm3uHM d p74E1. Synchronized java что это фото. Synchronized java что это-0*8zsm3uHM d p74E1. картинка Synchronized java что это. картинка 0*8zsm3uHM d p74E1

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

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

Синхронизация

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

Synchronized java что это. 0*uKx yo5kElJQ8pk. Synchronized java что это фото. Synchronized java что это-0*uKx yo5kElJQ8pk. картинка Synchronized java что это. картинка 0*uKx yo5kElJQ8pk

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

Следовательно, в этом сценарии два потока никогда не столкнутся.

Но является ли этот способ единственным для предотвращения состояния гонки?

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

Каждый объект в Java имеет Intrinsic Lock (монитор). Когда синхронизированный метод вызывается из потока, ему нужно получить этот монитор. Монитор будет освобождён после того, как поток завершит выполнение метода. Таким образом, мы можем синхронизировать блок инструкций, работающий с объектом, принудив потоки получать монитор, прежде чем выполнять блок инструкций. Помните, что монитор одновременно может удерживаться только одним потоком, поэтому другие потоки, желающие получить его, будут приостановлены до завершения работы текущего потока. Только после этого конкретный ожидающий поток сможет получить монитор и продолжить выполнение.

Единственный блок кода метода “doCountdown”, в который мы можем добавить ключевое слово synchronized, — это блок “цикла for”. Итак, какой же объект нам следует использовать для синхронизации цикла for? Переменную “i”? Не думаю, потому что это примитивный тип, а не объект. Монитор же присутствует только в объектах. А что насчёт объекта “color”? Давайте просто удалим synchronized из объявления метода и добавим следующим образом:

Вы видите тот же результат, что и на рисунке 5 в коде, где синхронизация не применялась. Почему же? Мы используем локальную переменную “color” для синхронизации. Как я уже пояснял выше относительно стеков потоков и прочего, использование локальной переменной здесь не работает, но объекты String переиспользуются внутри jvm, так как jvm для размещения строчных объектов использует пулы строк. Да, иногда это тоже может оказаться подходящим решением.

В качестве правила просто помните, что не нужно использовать локальную переменную для синхронизации.

Итак, давайте обновим синхронизированный блок кода таким образом:

Взглянув на результат, вы увидите, что потоки не столкнутся и не пропустят числа. Блок цикла for одновременно может выполняться только одним потоком.

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

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *