Вопросы по параллелизму из Java Guide - PullRequest
2 голосов
/ 04 января 2012

Итак, я читал о параллелизме и у меня есть несколько вопросов по пути ( руководство, которому я следовал - хотя я не уверен, что это лучший источник):

  1. Процессы и потоки. Разница в основном в том, что процесс - это программа в целом, а поток может быть (малой) частью программы?
  2. Я не совсем уверен, почему существует метод interrupted () и исключение InterruptedException. Зачем вообще использовать метод interrupted ()? Мне просто кажется, что Java просто добавляет дополнительный уровень косвенности.
  3. Что касается синхронизации (и особенно о той, что в этой ссылке), как добавление ключевого слова синхронизации даже решает проблему? Я имею в виду, что если поток A возвращает свой увеличенный c, а поток B возвращает уменьшенный c и сохраняет его в какой-то другой переменной, я не совсем уверен, как эта проблема решена. Я имею в виду, что это может быть ответом на мой собственный вопрос, но предполагается ли, что после того, как один из потоков вернет ответ, завершится? И если это так, то почему добавление синхронизации будет иметь значение?
  4. Я прочитал (из некоторого случайного PDF), что если у вас есть два Threads start () впоследствии, вы не можете гарантировать, что первый поток возникнет до второго потока. Как бы вы это гарантировали?
  5. В операторах синхронизации я не совсем уверен, какой смысл добавлять синхронизированный в метод. Что плохого в том, чтобы оставить это? Это потому, что ожидается, что оба мутируют отдельно, но будут получены вместе? Почему бы просто не иметь два несинхронизированных?
  6. Является ли volatile просто ключевым словом для переменных и является синонимом синхронизированного?
  7. Как проблема синхронизации в ситуации взаимоблокировки помогает? Чем эта ситуация отличается от запуска двух потоков, которые изменяют переменную?
  8. Кроме того, где находится "ожидание" / блокировка для другого человека, чтобы поклониться? Я бы подумал, что bow () заблокирован, а не bowBack ().

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

Ответы [ 2 ]

4 голосов
/ 04 января 2012

Ответы:

  1. Да, процесс - это процесс операционной системы с адресным пространством, поток - это единица выполнения, и в процессе может быть несколько единиц выполнения.
  2. Метод interrupt () и InterruptedException обычно используются для пробуждения потоков, которые ждут, чтобы они что-то сделали или завершили.
  3. Синхронизация - это форма взаимного исключения или блокировки, очень стандартная и необходимая в компьютерном программировании. Отыщите эти условия, прочитайте их и получите ответ.
  4. Правда, это не может быть гарантировано, вам понадобится какой-то механизм, включающий синхронизацию, которую используют потоки, чтобы убедиться, что они работают в нужном порядке. Это будет характерно для кода в потоках.
  5. См. Ответ на # 3
  6. Volatile - это способ убедиться, что конкретная переменная может быть правильно распределена между различными потоками. На многопроцессорных компьютерах (которые сейчас есть почти у каждого) необходимо убедиться, что значение переменной согласовано между процессорами. Это эффективный способ синхронизации одного значения.
  7. Прочтите о взаимоблокировке в более общих чертах, чтобы понять это. Как только вы впервые поймете взаимное исключение и блокировку, вы сможете понять, как могут возникать взаимоблокировки.
  8. Я не читал материалы, которые вы читали, поэтому я не понимаю этот. К сожалению.
2 голосов
/ 04 января 2012

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

Синхронное:

private Value value;

public void setValue(Value v) {
  value = v;
}

public void doSomething() {
  if(value != null) {
    doFirstThing();
    int val = value.getInt(); // Will throw NullPointerException if another
                              // thread calls setValue(null);
    doSecondThing(val);
  }
}

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

Для решения этой проблемы используйте синхронизацию:

private Value value;
private Object lock = new Object();

public void setValue(Value v) {
  synchronized(lock) {
    value = v;
  }
}

public void doSomething() {
  synchronized(lock) { // Prevents setValue being called by another thread.
    if(value != null) {
      doFirstThing();
      int val = value.getInt(); // Cannot throw NullPointerException.
      doSecondThing(val);
    }
  }
}

Volatile:

private boolean running = true;

// Called by Thread 1.
public void run() {
  while(running) {
    doSomething();
  }
}

// Called by Thread 2.
public void stop() {
  running = false;
}

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

public void run() {
  while(true) { // Will never end
    doSomething();
  }
}

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

Я не отвечал на ваши вопросы напрямую, как это сделал Фрэнсис. Я надеюсь, что эти примеры могут дать вам представление о концепциях лучше, чем примеры, которые вы видели в руководстве по Oracle.

...