java synchronized для чего

Ключевое слово Java synchronized, Синхронизированный метод и блок

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

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

Зачем нам нужна синхронизация?

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

Мы используем метод соединения потоков (), чтобы убедиться, что каждый поток мертв, прежде чем мы напечатаем окончательный подсчет.

Мы также используем случайный класс, чтобы добавить некоторое время обработки в метод run ().

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

Причиной такого расхождения является оператор “count++”. Это не атомная операция.

Сначала считывается переменная count, затем к ней добавляется 1, а затем значение присваивается переменной count.

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

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

Пример синхронизации Java

Давайте исправим вышеприведенную программу, используя ключевое слово synchronized. Мы можем создать синхронизированный блок вокруг операции “count++”.

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

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

Пример синхронизированного ключевого слова Java

Как синхронизированное ключевое слово работает внутри компании?

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

Блок синхронизации Java

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

Синтаксис синхронизированного блока

Вот простой пример синхронизированного блока в Java.

Метод синхронизации Java

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

Синтаксис синхронизированного метода

Вот пример метода синхронизации java.

Блокировка объекта в Синхронизированном методе

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

Метод синхронизации Java против блока

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

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

Вывод

Ключевое слово Java synchronized полезно для предотвращения повреждения данных при многопоточном программировании. Однако синхронизация снижает производительность кода из-за дополнительных накладных расходов на механизм блокировки. Использование синхронизированного блока или синхронизированного метода во многом зависит от требований вашего проекта.

Источник

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» ) ) ;
>

Источник

Руководство по ключевому слову Synchronized в Java

В этой статье рассматривается синхронизация потоков методов, статических методов и экземпляров в Java.

1. Обзор

Эта краткая статья будет введением к использованию блока synchronized в Java.

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

2. Почему Синхронизация?

Давайте рассмотрим типичное условие гонки, в котором мы вычисляем сумму и несколько потоков выполняют метод calculate() :

И давайте напишем простой тест:

Мы просто используем ExecutorService с 3-потоковой катушкой для выполнения calculate() 1000 раз.

Если бы мы выполняли это последовательно, ожидаемый результат был бы 1000, но наше многопоточное выполнение завершается неудачей почти каждый раз с несогласованным фактическим результатом, например:

Этот результат, конечно, не является неожиданным.

3. Ключевое слово Synchronized

Ключевое слово synchronized может использоваться на разных уровнях:

3.1. Методы синхронизированных экземпляров

Просто добавьте ключевое слово synchronized в объявление метода, чтобы сделать метод синхронизированным:

Обратите внимание, что как только мы синхронизируем метод, тестовый случай проходит, а фактический результат равен 1000:

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

3.2. Синхронизированные Статические методы

Статические методы синхронизированы точно так же, как методы экземпляра:

Давайте проверим это:

3.3. Синхронизированные Блоки Внутри Методов

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

Давайте проверим изменения:

Давайте протестируем блок внутри метода static :

3.4. Повторный вход

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

4. Заключение

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

Источник

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

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

Что такое synchronized

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

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

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

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

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

Пример

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

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

Для метода

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

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

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

Стоит знать

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

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

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

Источник

Сказочный портал