Вопрос

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

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

Решение

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

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

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

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

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

Другие советы

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

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 блокирует вызов метода test() следующего потока, пока выполнение предыдущего потока не завершено.Потоки могут обращаться к этому методу по одному.Без synchronized все потоки могут получить доступ к этому методу одновременно.

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

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

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

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 Ключевое слово предотвращает одновременный доступ к блоку кода или объекту несколькими потоками.По умолчанию Hashtable является synchronized, поэтому только один поток может одновременно обращаться к таблице.

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

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

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

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

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

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

Учти это:

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

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

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

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

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

Обзор

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

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

Глубже

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

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

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

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

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

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

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

Технический

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

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

Заключение

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

Источники

http://docs.oracle.com/javase/specs/jls/se8/html/index.html
Спецификация языка Java®, 13 февраля 2015 г.

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

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

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

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

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

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

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

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

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

Более подробная информация из документации Java страница

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

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

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

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

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

Синхронизация методов имеет два последствия:

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

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

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

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

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

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

Вот объяснение от Учебники по 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, то синхронизация этих методов имеет два эффекта:

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

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 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

  • Каждый объект/класс имеет intrinsic lock связанный с этим.
  • Когда поток вызывает synchronized statement, он автоматически приобретает intrinsic lock для этого synchronized statement's объект и освобождает его, когда метод возвращается.Пока поток владеет intrinsic lock, НИКАКОГО другого поток может приобрести ТАКОЙ ЖЕ lock => потокобезопасный.

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

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

ЖЕ ЗАМОК => блокировка (не зависит от того, какой метод?или какие утверждения?)

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

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

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

Примечание

(это не имеет большого значения для synchronized, это разница между объектом и классом или нестатическим и статическим).

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

Ссылка

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

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

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

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

Одним из таких примеров является Конкурентлинкеддек.Вместе с шаблон команды он позволяет создавать высокоэффективные рабочие потоки, помещая команды в параллельную очередь - не требуется явная синхронизация, невозможны взаимоблокировки, не требуется явная функция Sleep(), просто опрашивайте очередь, вызывая take().

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

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

Такое неявное поведение является несколько пагубным аспектом, поскольку из-за него большинство Java-программистов без особого опыта будут воспринимать многое как данность.А затем внезапно наткнулся на эту ветку после того, как Java не делает то, что «должен» делать в рабочей среде, где другая рабочая нагрузка — и довольно сложно тестировать проблемы параллелизма.

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

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();
    }
}

Мы создали два объекта класса MyRunnable: runnable1 используется совместно с потоком 1 и потоком 3, а runnable2 используется только с потоком 2.Теперь, когда t1 и t3 запускаются без использования синхронизации, вывод PFB предполагает, что оба потока 1 и 3 одновременно влияют на значение var, где для потока 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 поток 3 ожидает завершения потока 1 во всех сценариях.Имеются две блокировки: одна на runnable1, совместно используемая потоком 1 и потоком 3, а другая на runnable2, совместно используемая только потоком 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

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

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

Object.wait()

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top