Является ли «синхронизированный» действительно просто синтаксическим сахаром? - PullRequest
6 голосов
/ 26 июня 2010

Я новичок в многопоточности, и я написал этот код, который печатает числа 1-10000, имея параллельно работающие потоки, увеличивающие и выводящие переменную.

Вот код, который я использую:

package threadtest;

public class Main{

    static int i=0;
    static Object lock=new Object();

    private static class Incrementer extends Thread{

        @Override
        public void run(){
            while (true){
                synchronized(lock){
                        if (i>=10000)
                            break;
                        i++;
                        System.out.println(i);
                }
            }               
        }
    }


    public static void main(String[] args) {
        new Incrementer().start();
        new Incrementer().start();
        new Incrementer().start();
        new Incrementer().start();
        new Incrementer().start();
        new Incrementer().start();
    }
}

Это работает - я написал тестовую программу для проверки выходных данных, и напечатанные числа имеют порядок 1-10000 по порядку.

У меня такой вопрос: я слышал, что synchronizedэто только синтаксический сахар.Но я не могу добиться успешного результата без его использования.Чего мне не хватает?

Ответы [ 5 ]

14 голосов
/ 26 июня 2010

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

Если в синтаксических блокировках в Java есть своего рода «синтаксический сахар», то synchronized может применяться к блокам (как выСделали это выше) и целыми методами.Следующие два метода примерно эквивалентны по семантике:

synchronized void method1() {
  // ... do stuff ...
}

void method2() {
  synchronized(this) {
    // ... do stuff ...
  }
}

Так зачем вам делать вторую версию вместо первой?

  • Синхронизированные вызовы методов выполняются намного медленнее, чемвызовы простого старого метода, примерно на порядок.Если ваш синхронизированный код не гарантированно всегда выполняется (скажем, в условном выражении), то вы, вероятно, не хотите синхронизировать весь метод.
  • Синхронизированные методы удерживают блокировки дольше, чем синхронизированные блоки (из-завсе настройки метода / свернуть код).Второй метод, описанный выше, будет удерживать блокировку в течение меньшего времени, потому что время, потраченное на настройку и удаление кадра стека, не будет заблокировано.
  • Вы можете гораздо лучше контролировать то, что блокируете, если выиспользуйте синхронизированные блоки.
  • (Предоставлено starblue ) Синхронизированные блоки могут использовать для блокировки объекты, отличные от this, что обеспечивает более гибкую семантику блокировки.
1 голос
/ 27 июня 2010

Конечно, «синхронизированный» - это просто синтаксический сахар - экстремальный полезный синтаксический сахар.

Если вам нужны java-программы без сахара, вы должны писать прямо в байт-коде java: monitorenter , monitorexit , lock и разблокировать операции, указанные в Технические характеристики виртуальной машины 8.13 Блокировки и синхронизация

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

Синхронизированный оператор вычисляет ссылка на объект; тогда пытается выполнить операцию блокировки на этом объекте и не продолжается дальше, пока операция блокировки не успешно завершено. (Замок операция может быть отложена, потому что правила о замках могут помешать основным память от участия до некоторых другой поток готов выполнить один или более операций разблокировки.) После операция блокировки была выполнена, Тело синхронизированного оператора казнены. Обычно компилятор для Язык программирования Java гарантирует, что операция блокировки, осуществляемая выполнено указание монитора до казни тела синхронизированный оператор совпадает с помощью операции разблокировки, выполненной инструкция monitorexit всякий раз, когда синхронизированный оператор завершается, является ли завершение нормальным или крут.

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

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

Хотя компилятор для Java язык программирования нормально гарантирует структурированное использование замков (см. раздел 7.14 «Синхронизация»), нет никакой гарантии, что весь код отправлено на виртуальную машину Java будет подчиняться этому свойству. Реализации виртуальной Java машины разрешены, но не обязательны обеспечить соблюдение обоих из следующих двух правила, гарантирующие структурированную блокировку.

Пусть T - нить, а L - замок. Тогда:

  1. Количество операций блокировки, выполненных T на L во время метода вызов должен равняться количеству разблокировать операции, выполненные т на л во время вызова метода, вызов метода завершается нормально или резко.

  2. Ни при каких условиях во время вызова метода число разблокировок не может операции, выполняемые T на L, так как вызов метода превышает количество операций блокировки, выполненных T на L с момента вызова метода.

В менее формальных условиях, во время метода вызов каждой операции разблокировки на L должен соответствовать некоторому предыдущему замку операция на Л.

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

1 голос
/ 27 июня 2010

На самом деле, начиная с Java 5, у вас (формально) есть альтернативный набор инструментов в java.util.concurrent.Смотрите здесь для более подробной информации.Как подробно описано в статье, модель блокировки монитора, предоставляемая на уровне языка Java, имеет ряд существенных ограничений и может быть трудно рассуждать, когда существует сложный набор взаимозависимых объектов и отношений блокировки, делающих живую блокировку реальной возможностью.Библиотека java.util.concurrent предлагает семантику блокировки, которая может быть более знакома программистам, имеющим опыт работы с POSIX-подобными системами

1 голос
/ 26 июня 2010

Похоже, ваши источники просто не правы. Ключевое слово syncrhonized важно использовать - и использовать правильно - при написании поточно-ориентированного кода. И, похоже, ваши собственные эксперименты подтверждают это.

Подробнее о синхронизации в Java:

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

Java-блокировки и синхронизированные операторы

0 голосов
/ 26 июня 2010

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

synchronized(MyClass.class){
 //code to be executed in the static context
}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...