'Синхронизируется' действительно просто синтаксический сахар?

Я плохо знаком с многопоточностью, и я написал этот код, который печатает номера 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 только синтаксический сахар. Но я, может казаться, не достигаю успешного результата, не используя его. Что я пропускаю?

6
задан Cam 26 June 2010 в 16:49
поделиться

5 ответов

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

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

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

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

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

  • Вызов синхронизированных методов намного медленнее, чем вызовы простых старых методов, примерно на порядок . Если ваш синхронизированный код не всегда будет выполняться (скажем, в условном выражении), то вы, вероятно, не захотите синхронизировать весь метод.
  • Синхронизированные методы удерживают блокировки дольше, чем синхронизированные блоки (из-за всего кода установки / отключения метода). Второй метод, описанный выше, будет удерживать блокировку меньше времени, потому что время, потраченное на настройку и удаление фрейма стека, не будет заблокировано.
  • Вы можете иметь гораздо более точный контроль над тем, что именно вы блокируете, если вы используете синхронизированные блоки.
  • (Любезно предоставлено starblue ) Синхронизированные блоки могут использовать для блокировки объекты, отличные от this , что дает вам более гибкую семантику блокировки.
14
ответ дан 8 December 2019 в 13:43
поделиться

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

Дополнительные сведения о синхронизации в Java:

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

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

1
ответ дан 8 December 2019 в 13:43
поделиться

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

.
1
ответ дан 8 December 2019 в 13:43
поделиться

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

Если вам нужны Java-программы без сахара, вы должны писать непосредственно в байтовом Java-коде monitorenter , monitorexit , lock и операции разблокировки , указанные в Спецификации VM 8.13 Блокировки и синхронизация

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

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

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

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

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

Пусть T - поток, а L - замок. Затем:

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

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

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

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

1
ответ дан 8 December 2019 в 13:43
поделиться

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

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

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

0
ответ дан 8 December 2019 в 13:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: