1. Основное использование синхронизированного
Синхронизированный является наиболее часто используемым методом для решения проблем параллелизма в Java и самом простом методе. Синхронизированный имеет три основные функции: (1) Обеспечить взаимодействие кода синхронизации синхронизации доступа (2) Убедитесь, что модификация общих переменных может быть своевременно видимой (3) эффективно решить проблему повторного порядка. Синхронизированный имеет три применения синхронизации:
(1) обычный метод изменения
(2) Изменить статические методы
(3) Изменить кодовый блок
Затем я буду использовать несколько примеров программ для иллюстрации этих трех методов использования (ради сравнения, за исключением различных методов синхронизации использования, другие три кода в основном согласованы).
1. Нет синхронизации:
Код фрагмент 1:
пакет com.paddx.test.concurrent; public class synchronizedtest {public void method1 () {System.out.println ("Метод 1 Start"); try {System.out.println ("Метод 1 execute"); Thread.sleep (3000); } catch (прерванное искусство e) {e.printstacktrace (); } System.out.println ("Метод 1 End"); } public void method2 () {System.out.println ("Метод 2 Start"); try {System.out.println ("Method 2 execute"); Thread.sleep (1000); } catch (прерванное искусство e) {e.printstacktrace (); } System.out.println ("Метод 2 End"); } public static void main (string [] args) {final SynchronizedTest test = new SynchronizedTest (); новый поток (new Runnable () {@Override public void run () {test.method1 ();}}). start (); новый поток (new Runnable () {@Override public void run () {test.method2 ();}}). start (); }}Результат выполнения выглядит следующим образом: поток 1 и поток 2 введите состояние выполнения одновременно. Поток 2 выполняется быстрее, чем поток 1, поэтому поток 2 выполняется первым. В этом процессе поток 1 и поток 2 выполняются одновременно.
Метод 1 запуск
Метод 1 выполнить
Метод 2 старт
Метод 2 выполнить
Метод 2 конец
Метод 1 конец
2. Синхронизируйте общие методы:
Код фрагмент два:
пакет com.paddx.test.concurrent; public class synchronizedtest {public synchronized void method1 () {System.out.println ("Метод 1 Start"); try {System.out.println ("Метод 1 execute"); Thread.sleep (3000); } catch (прерванное искусство e) {e.printstacktrace (); } System.out.println ("Метод 1 End"); } public synchronized void method2 () {System.out.println ("Метод 2 Start"); try {System.out.println ("Method 2 execute"); Thread.sleep (1000); } catch (прерванное искусство e) {e.printstacktrace (); } System.out.println ("Метод 2 End"); } public static void main (string [] args) {final SynchronizedTest test = new SynchronizedTest (); новый поток (new Runnable () {@Override public void run () {test.method1 ();}}). start (); новый поток (new Runnable () {@Override public void run () {test.method2 ();}}). start (); }}Результат выполнения выглядит следующим образом. После сравнения его с сегментом кода можно ясно видеть, что поток 2 должен ждать выполнения метода 1 потока 1 для завершения, прежде чем начать выполнять метод Method2.
Метод 1 запуск
Метод 1 выполнить
Метод 1 конец
Метод 2 старт
Метод 2 выполнить
Метод 2 конец
3. Статический метод (класс) синхронизация
Код фрагмент три:
пакет com.paddx.test.concurrent; public class synchronizedtest {public static synchronized void method1 () {System.out.println ("Метод 1 Start"); try {System.out.println ("Метод 1 execute"); Thread.sleep (3000); } catch (прерванное искусство e) {e.printstacktrace (); } System.out.println ("Метод 1 End"); } public static synchronized void method2 () {System.out.println ("Метод 2 Start"); try {System.out.println ("Method 2 execute"); Thread.sleep (1000); } catch (прерванное искусство e) {e.printstacktrace (); } System.out.println ("Метод 2 End"); } public static void main (string [] args) {final SynchronizedTest test = new SynchronizedTest (); final SynchronizedTest test2 = new SynchronizedTest (); новый поток (new Runnable () {@Override public void run () {test.method1 ();}}). start (); новый поток (new Runnable () {@Override public void run () {test2.method2 ();}}). start (); }}Результат выполнения выглядит следующим образом. Синхронизация статических методов является по сути синхронизацией классов (статические методы по существу являются методами класса, а не методами на объектах). Следовательно, даже если тест и тест 2 принадлежат к разным объектам, они оба принадлежат к экземплярам класса SynchronizedTest, поэтому метод1 и метод2 могут быть выполнены только последовательно и не могут быть выполнены одновременно.
Метод 1 запуск
Метод 1 выполнить
Метод 1 конец
Метод 2 старт
Метод 2 выполнить
Метод 2 конец
4. Синхронизация блока кода
Код фрагмент четыре:
пакет com.paddx.test.concurrent; public class synchronizedtest {public void method1 () {System.out.println ("Метод 1 Start"); try {synchronized (this) {System.out.println ("Метод 1 execute"); Thread.sleep (3000); }} catch (прерывание Exception e) {e.printStackTrace (); } System.out.println ("Метод 1 End"); } public void method2 () {System.out.println ("Метод 2 Start"); try {synchronized (this) {System.out.println ("Метод 2 Execute"); Thread.sleep (1000); }} catch (прерывание Exception e) {e.printStackTrace (); } System.out.println ("Метод 2 End"); } public static void main (string [] args) {final SynchronizedTest test = new SynchronizedTest (); новый поток (new Runnable () {@Override public void run () {test.method1 ();}}). start (); новый поток (new Runnable () {@Override public void run () {test.method2 ();}}). start (); }}Результат выполнения выглядит следующим образом. Хотя и поток 1, и поток 2 введите соответствующий метод и запуск выполнения, потоку 2 необходимо ждать выполнения блока синхронизации в потоке 1, чтобы завершить до входа в блок синхронизации.
Метод 1 запуск
Метод 1 выполнить
Метод 2 старт
Метод 1 конец
Метод 2 выполнить
Метод 2 конец
2. Синхронизированный принцип
Если у вас все еще есть вопросы о приведенных выше результатах выполнения, не волнуйтесь. Давайте сначала поймем принцип синхронизации, а затем посмотрим на вышеупомянутые вопросы, чтобы увидеть с первого взгляда. Давайте сначала рассмотрим, как синхронизированный код синхронизирует блоки кода, разместите следующий код:
пакет com.paddx.test.concurrent; public class synchronizeddemo {public void method () {synchronized (this) {System.out.println ("Метод 1 Start"); }}}Результат декомпиляции:
Что касается роли этих двух инструкций, мы напрямую относимся к описанию в спецификации JVM:
Монитор:
Каждый объект связан с монитором. Монитор заблокирован тогда и только тогда, когда у него есть владелец. Поток, который выполняет попытки Monitorenter, получить право собственности на монитор, связанный с objectref, следующим образом: • Если количество вводов монитора, связанного с objectref, равен нулю, поток входит в монитор и устанавливает его количество входа. Затем поток является владельцем монитора. • Если поток уже владеет монитором, связанным с objectref, он возвращается к монитору, увеличивая количество входа. • Если другой поток уже владеет монитором, связанным с objectref, потоки блокируются до тех пор, пока количество въездов монитора не станет нулю, то снова пытается получить право собственности.
Общее значение этого отрывка:
Каждый объект имеет блокировку монитора (монитор). Когда монитор занят, он будет заблокирован. Когда поток выполняет инструкцию мониторинга, он пытается получить право собственности на монитор. Процесс заключается в следующем:
1. Если количество ввода монитора составляет 0, поток входит в монитор, а затем устанавливает номер входа на 1, поток является владельцем монитора.
2. Если поток уже владеет монитором и просто повторно входит, количество входа в монитор добавляется в 1.
3. Если другие потоки заняли монитор, поток попадает в состояние блокировки до тех пор, пока количество входа монитора не станет 0, а затем попытаться снова получить право собственности на монитор.
мониторексит:
Поток, который выполняет мониторексит, должен быть владельцем монитора, связанного с экземпляром, на который ссылается objectref. Поток уменьшает количество входа монитора, связанного с objectref. Если в результате значение количества записей равно нулю, поток выходит из монитора и больше не является его владельцем. Другие потоки, которые блокируют для входа в монитор, разрешено попытаться сделать это.
Общее значение этого отрывка:
Поток, выполняющий мониторексит, должен быть владельцем монитора, соответствующего objectref.
Когда инструкция выполняется, число въезда монитора уменьшается на 1. Если количество въезда монитора составляет 0 после уменьшения на 1, поток выходит из монитора и больше не является владельцем этого монитора. Другие потоки, заблокированные этим монитором, могут попытаться получить право собственности на этот монитор.
Через эти два параграфа описания мы должны быть в состоянии четко увидеть принцип реализации синхронизации. Семантический базовый слой синхронизированного завершается через объект монитора. Фактически, подождите/уведомление и другие методы также полагаются на объекты монитора. Вот почему только такие методы, как ожидание/уведомление, могут быть вызваны синхронизированными блоками или методами, в противном случае будет брошено исключение java.lang.illegalmonitorstateexception.
Давайте посмотрим на результаты декомпиляции метода синхронизации:
исходный код:
пакет com.paddx.test.concurrent; public class synchronizedmethod {public synchronized void method () {System.out.println ("Привет, мир!"); }}Результат декомпиляции:
Судя по результатам декомпиляции, синхронизация метода не завершается через монитор инструкций и мониторексит (теоретически, она также может быть реализована с помощью этих двух инструкций). Однако, по сравнению с обычными методами, в его постоянный пул добавляется идентификатор ACC_Synchronized. JVM реализует синхронизацию методов, основанных на этом идентификаторе: Когда метод вызван, призывная инструкция проверит, устанавливается ли установлен флаг доступа ACC_SYNCHRONIZED метода. Если установлено, поток выполнения сначала получит монитор, а затем выполнит тело метода после успешного выполнения метода. После выполнения метода монитор будет выпущен. Во время выполнения метода ни один другой поток больше не может получить тот же объект монитора. На самом деле, нет никакой разницы в сущности, но синхронизация метода является неявным способом достижения его без необходимости сделать с помощью байт -кода.
3. Объяснение результатов работы
С пониманием принципа синхронизации вы можете легко решить его, посмотрев на вышеупомянутую программу.
1. Сегмент кода 2 Результаты:
Хотя метод1 и метод2 являются разными методами, оба метода синхронизируются и вызываются через один и тот же объект. Поэтому, перед вызовом, вам необходимо конкурировать за блокировку (монитор) на том же объекте, чтобы вы могли получить только блокировки. Следовательно, метод1 и метод2 могут быть выполнены только последовательно.
2. Сегмент кода 3 Результаты:
Хотя Test и Test2 принадлежат к разным объектам, тест и тест 2 принадлежат к разным случаям одного и того же класса. Поскольку Method1 и Method2 принадлежат к методам статической синхронизации, вам необходимо получить монитор в одном классе (каждый класс соответствует только одному объекту класса), так что вы можете выполнять только последовательно.
3. Сегмент кода 4 Результаты:
Для синхронизации кодовых блоков по существу необходимо получить монитор объекта в скобках после синхронизированного ключевого слова. Поскольку содержимое кронштейнов в этом коде является этим, а метод1 и метод 2 вызываются через один и тот же объект, поэтому перед входом в блок синхронизации вам необходимо конкурировать за блокировки на одном и том же объекте, чтобы блок синхронизации мог быть выполнен только в последовательности.
Четыре резюме
Синхронизированный является наиболее часто используемым методом безопасности потока в одновременном программировании Java, и он относительно прост в использовании. Однако, если мы сможем понять его принципы и иметь некоторое понимание основных знаний, таких как блокировки монитора, это может помочь нам правильно использовать синхронизированные ключевые слова, и, с другой стороны, это также может помочь нам лучше понять механизм программирования параллельного программирования, помочь нам выбрать лучшие стратегии параллелизма для выполнения задач в разных обстоятельствах. Вы также можете спокойно справиться с различными параллельными проблемами, с которыми вы сталкиваетесь в повседневной жизни.