Что означает «синхронизированный»?

У меня есть некоторые вопросы относительно использования и значимости synchronized ключевого слова.

  • Каково значение synchronized ключевого слова?
  • Когда следует synchronized методы?
  • Что значит программно и логически?

synchronized ключевое слово – это все разные чтения и записи streamов для тех же переменных, объектов и ресурсов. Это не тривиальная тема в Java, но вот цитата из Sun:

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

В очень, очень малой части: когда у вас есть два streamа, которые читают и записывают в один и тот же «ресурс», скажем, переменную с именем foo , вам нужно убедиться, что эти streamи обращаются к переменной в атомном режиме. Без synchronized ключевого слова ваш stream 1 может не увидеть stream изменений 2, сделанный для foo , или, что еще хуже, его можно изменить только наполовину. Это не то, что вы логически ожидаете.

Опять же, это нетривиальная тема в Java. Чтобы узнать больше, изучите здесь темы о SO и Interwebs о:

  • совпадение
  • Модель памяти Java

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

Ну, я думаю, у нас было достаточно теоретических объяснений, поэтому рассмотрим этот код

 public class SOP { public static void print(String s) { System.out.println(s+"\n"); } } public class TestThread extends Thread { String name; TheDemo theDemo; public TestThread(String name,TheDemo theDemo) { this.theDemo = theDemo; this.name = name; start(); } @Override public void run() { theDemo.test(name); } } public class TheDemo { public synchronized void test(String name) { for(int i=0;i<10;i++) { SOP.print(name + " :: "+i); try{ Thread.sleep(500); } catch (Exception e) { SOP.print(e.getMessage()); } } } public static void main(String[] args) { TheDemo theDemo = new TheDemo(); new TestThread("THREAD 1",theDemo); new TestThread("THREAD 2",theDemo); new TestThread("THREAD 3",theDemo); } } 

Примечание: synchronized блокирует вызов следующего streamа методу метода (), пока выполнение предыдущего streamа не завершено. Потоки могут получить доступ к этому методу по одному за раз. Без synchronized все streamи могут одновременно обращаться к этому методу.

Когда stream вызывает синхронизированный метод «test» объекта (здесь объект является экземпляром classа «TheDemo»), он получает блокировку этого объекта, любой новый stream не может вызывать ЛЮБОЙ синхронизированный метод того же объекта, пока предыдущий stream который приобрел замок, не освобождает замок.

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

Выход с синхронизированным

 THREAD 1 :: 0 THREAD 1 :: 1 THREAD 1 :: 2 THREAD 1 :: 3 THREAD 1 :: 4 THREAD 1 :: 5 THREAD 1 :: 6 THREAD 1 :: 7 THREAD 1 :: 8 THREAD 1 :: 9 THREAD 3 :: 0 THREAD 3 :: 1 THREAD 3 :: 2 THREAD 3 :: 3 THREAD 3 :: 4 THREAD 3 :: 5 THREAD 3 :: 6 THREAD 3 :: 7 THREAD 3 :: 8 THREAD 3 :: 9 THREAD 2 :: 0 THREAD 2 :: 1 THREAD 2 :: 2 THREAD 2 :: 3 THREAD 2 :: 4 THREAD 2 :: 5 THREAD 2 :: 6 THREAD 2 :: 7 THREAD 2 :: 8 THREAD 2 :: 9 

Выход без синхронизации

 THREAD 1 :: 0 THREAD 2 :: 0 THREAD 3 :: 0 THREAD 1 :: 1 THREAD 2 :: 1 THREAD 3 :: 1 THREAD 1 :: 2 THREAD 2 :: 2 THREAD 3 :: 2 THREAD 1 :: 3 THREAD 2 :: 3 THREAD 3 :: 3 THREAD 1 :: 4 THREAD 2 :: 4 THREAD 3 :: 4 THREAD 1 :: 5 THREAD 2 :: 5 THREAD 3 :: 5 THREAD 1 :: 6 THREAD 2 :: 6 THREAD 3 :: 6 THREAD 1 :: 7 THREAD 2 :: 7 THREAD 3 :: 7 THREAD 1 :: 8 THREAD 2 :: 8 THREAD 3 :: 8 THREAD 1 :: 9 THREAD 2 :: 9 THREAD 3 :: 9 

synchronized ключевое слово предотвращает параллельный доступ к блоку кода или объекта несколькими streamами. По умолчанию Hashtable synchronized , поэтому только один stream может одновременно обращаться к таблице.

При использовании non-synchronized конструкций, таких как HashMap , вы должны создавать функции безопасности streamов в своем коде, чтобы предотвратить ошибки согласованности памяти.

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

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

Если ваше приложение однопоточно, synchronized блоки не предоставляют преимуществ.

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

Это часто называют созданием classа streamобезопасным, но я бы сказал, что это эвфемизм. Хотя верно, что синхронизация защищает внутреннее состояние Vector от повреждения, это обычно не помогает пользователю Vector.

Учти это:

  if (vector.isEmpty()){ vector.add(data); } 

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

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

Поскольку синхронизация на уровне метода является a) дорогой, когда она вам не нужна, и b) недостаточно, когда вам нужна синхронизация, теперь есть несинхронизированные замены (ArrayList в случае Vector).

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

обзор

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

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

Глубже

Синтаксически synchronized ключевое слово принимает Object как его параметр (называемый объектом блокировки ), за которым следует { block of code } .

  • Когда выполнение встречает это ключевое слово, текущий stream пытается «блокировать / приобретать / владеть» (выбирать) объект блокировки и выполнять соответствующий блок кода после того, как блокировка была приобретена.

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

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

Синхронизированные методы:

Добавление synchronized ключевого слова в определение метода равно всему телу метода, который обернут в синхронизированный блок кода, причем объект блокировки является this (например, методы) и ClassInQuestion.getClass() (для методов classа) .

– Метод экземпляра – это метод, который не имеет static ключевого слова.
Метод classа – это метод, который имеет static ключевое слово.

технический

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

Недостаточно выполнить операцию записи в streamе до (настенное время) другой stream читает его, потому что аппаратное обеспечение может кэшировать значение переменной, а stream чтения будет видеть кешированное значение вместо того, что было написано для Это.

Вывод

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

источники

http://docs.oracle.com/javase/specs/jls/se8/html/index.html
Спецификация Java® Language, 2015-02-13

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

Что такое синхронизированное ключевое слово?

Потоки передаются, главным образом, путем совместного доступа к полям и полям ссылок на объекты. Эта форма коммуникации чрезвычайно эффективна, но делает возможными два вида ошибок: помехи streamов и ошибки согласованности памяти . Инструмент, необходимый для предотвращения этих ошибок, – это синхронизация.

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

Когда синхронизируются методы?

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

Что означает про грамматически и логически?

Это означает, что только один stream может получить доступ к критическому разделу путем приобретения блокировки. Если этот stream не освободит эту блокировку, все остальные нити (ы) придется ждать, чтобы получить блокировку. У них нет доступа для входа в критический раздел без блокировки.

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

Подробнее о странице документации java

Внутренние замки и синхронизация:

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

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

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

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

Синхронизация методов синхронизации имеет два эффекта :

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

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

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

Это гарантирует, что изменения состояния объекта будут видны для всех streamов.

Ищите другие альтернативы синхронизации в:

Избегайте синхронизации (это) в Java?

Насколько я понимаю, синхронизация в основном означает, что компилятор пишет monitor.enter и monitor.exit вокруг вашего метода. Как таковой он может быть streamобезопасным в зависимости от того, как он используется (я имею в виду, что вы можете написать объект с синхронизированными методами, который не является streamобезопасным в зависимости от того, что делает ваш class).

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

Рассмотрим следующий код:

 public class SynchronizedCounter { private int c = 0; public synchronized void increment() { c++; } public synchronized void decrement() { c--; } public synchronized int value() { return c; } } 

если count – это экземпляр SynchronizedCounter то SynchronizedCounter этих методов имеет два эффекта:

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

Synchronized normal method эквивалентный Synchronized statement (используйте это)

 class A { public synchronized void methodA() { // all function code } equivalent to public void methodA() { synchronized(this) { // all function code } } } 

Synchronized static method эквивалентный Synchronized statement (class использования)

 class A { public static synchronized void methodA() { // all function code } equivalent to public void methodA() { synchronized(A.class) { // all function code } } } 

Синхронизированный оператор (с использованием переменной)

 class A { private Object lock1 = new Object(); public void methodA() { synchronized(lock1 ) { // all function code } } } 

Для synchronized мы имеем как Synchronized Methods и Synchronized Statements . Однако Synchronized Methods похожи на Synchronized Statements поэтому нам просто нужно понять Synchronized Statements .

=> В принципе, у нас будет

 synchronized(object or class) { // object/class use to provides the intrinsic lock // code } 

Вот 2 думают, что помогают понять synchronized

  • Каждый объект / class имеет связанный с ним intrinsic lock .
  • Когда stream вызывает synchronized statement , он автоматически получает intrinsic lock для объекта synchronized statement's и освобождает его при возврате метода. Пока stream владеет intrinsic lock , NO другой stream может получить SAME lock => thread safe.

=> Когда thread A вызывает synchronized(this){// code 1} => весь блок-код (внутри classа), где synchronized(this) и весь synchronized normal method (внутри classа) заблокирован, потому что SAME заблокирован. Он будет выполняться после разблокировки thread A («// code 1» завершен).

Это поведение похоже на synchronized(a variable){// code 1} или synchronized(class) .

SAME LOCK => блокировка (не зависит от того, какой метод? Или какие заявления?)

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

Я предпочитаю synchronized statements потому что он более расширяем. Например, в будущем вам потребуется только синхронизация части метода. Например, у вас есть 2 синхронизированный метод, и он не имеет никакого отношения к друг другу, однако, когда stream запускает метод, он блокирует другой метод (он может предотвратить использование synchronized(a variable) ).

Однако применять синхронизированный метод просто, и код выглядит просто. Для некоторого classа существует только один синхронизированный метод или все синхронизированные методы в classе, относящиеся друг к другу => мы можем использовать synchronized method чтобы сделать код короче и легко понятным

Заметка

(он не имеет большого отношения к synchronized , он отличается от объекта и classа или нестационарный и статический).

  • Когда вы используете synchronized или нормальный метод или synchronized(this) или synchronized(non-static variable) он будет синхронизироваться с базой на каждом экземпляре объекта.
  • Когда вы используете synchronized или статический метод или synchronized(class) или synchronized(static variable) он будет синхронизирован базой по classу

Справка

https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html

Надеюсь, что это поможет

Какие другие ответы отсутствуют, это один важный аспект: барьеры памяти . Синхронизация streamов в основном состоит из двух частей: сериализации и видимости. Я советую всем google «барьер памяти jvm», поскольку это нетривиальная и чрезвычайно важная тема (если вы изменяете общие данные, к которым обращаются несколько streamов). Сделав это, я советую посмотреть classы пакета java.util.concurrent, которые помогают избежать использования явной синхронизации, что, в свою очередь, помогает поддерживать простые и эффективные программы, возможно, даже предотвращая взаимоблокировки.

Одним из таких примеров является ConcurrentLinkedDeque . Вместе с командным шаблоном он позволяет создавать высокоэффективные рабочие streamи, набирая команды в параллельную очередь – не требуется явная синхронизация, нет взаимоблокировок, нет явного сна (), необходимо просто опросить очередь, вызвав take ().

Короче говоря, «синхронизация памяти» происходит неявно при запуске streamа, stream заканчивается, вы читаете переменную volatile, вы разблокируете монитор (оставляете синхронизированный блок / функцию) и т. Д. Эта «синхронизация» влияет (в некотором смысле «флеш» ») все записи делаются до этого конкретного действия. В случае вышеупомянутого ConcurrentLinkedDeque документация «говорит»:

Эффекты согласованности памяти. Как и в случае с другими параллельными коллекциями, действия в streamе перед размещением объекта в ConcurrentLinkedDeque происходят до действий после доступа или удаления этого элемента из ConcurrentLinkedDeque в другом streamе.

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

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

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

 Object.wait() 

Синхронизированное просто означает, что несколько streamов, если они связаны с одним объектом, могут предотвратить загрязнение чтения и записи, если синхронизируемый блок используется для конкретного объекта. Чтобы дать вам больше ясности, давайте возьмем пример:

 class MyRunnable implements Runnable { int var = 10; @Override public void run() { call(); } public void call() { synchronized (this) { for (int i = 0; i < 4; i++) { var++; System.out.println("Current Thread " + Thread.currentThread().getName() + " var value "+var); } } } } public class MutlipleThreadsRunnable { public static void main(String[] args) { MyRunnable runnable1 = new MyRunnable(); MyRunnable runnable2 = new MyRunnable(); Thread t1 = new Thread(runnable1); t1.setName("Thread -1"); Thread t2 = new Thread(runnable2); t2.setName("Thread -2"); Thread t3 = new Thread(runnable1); t3.setName("Thread -3"); t1.start(); t2.start(); t3.start(); } } 

Мы создали два объекта classа MyRunnable, а runnable1 - совместно с streamом 1, а stream 3 и runnable2 - только с streamом 2. Теперь, когда t1 и t3 запускаются без использования синхронизации, вывод PFB, который предполагает, что оба streamа 1 и 3 одновременно влияют на значение var, где для streamа 2 var имеет свою собственную память.

 Without Synchronized keyword Current Thread Thread -1 var value 11 Current Thread Thread -2 var value 11 Current Thread Thread -2 var value 12 Current Thread Thread -2 var value 13 Current Thread Thread -2 var value 14 Current Thread Thread -1 var value 12 Current Thread Thread -3 var value 13 Current Thread Thread -3 var value 15 Current Thread Thread -1 var value 14 Current Thread Thread -1 var value 17 Current Thread Thread -3 var value 16 Current Thread Thread -3 var value 18 

Используя Synchronzied, stream 3 ожидает завершения streamа 1 во всех сценариях. Имеются две блокировки, одна на runnable1, совместно используемая нитью 1 и streamом 3, а другая на runnable2, совместно используемая только streamом 2.

 Current Thread Thread -1 var value 11 Current Thread Thread -2 var value 11 Current Thread Thread -1 var value 12 Current Thread Thread -2 var value 12 Current Thread Thread -1 var value 13 Current Thread Thread -2 var value 13 Current Thread Thread -1 var value 14 Current Thread Thread -2 var value 14 Current Thread Thread -3 var value 15 Current Thread Thread -3 var value 16 Current Thread Thread -3 var value 17 Current Thread Thread -3 var value 18 

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

  • Какова цель ключевого слова var и когда я должен использовать его (или опустить)?
  • Существует ли альтернатива ANSI SQL для ключевого слова MYSQL LIMIT?
  • Как заставить VS 2010 распознавать определенные функции CUDA
  • Используя ключевое слово «this» в java
  • Что такое родное ключевое слово в Java?
  • Когда следует использовать новое ключевое слово в C ++?
  • Когда мы должны использовать ключевое слово extern alias в C #?
  • Что эквивалентно ключевому слову C # 'var' в Java?
  • В чем разница между ключевыми словами «ref» и «out»?
  • «Новое» ключевое слово в Scala
  • Зарезервированное ключевое слово Gson Java
  • Давайте будем гением компьютера.