На презентации Paul Tyma я нашел вопрос об интервью:
Что более твердо, синхронизируя 2 потока или синхронизируя 1 000 потоков?
С моей точки зрения конечно, синхронизация 1 000 потоков более трудна, но я не могу думать о серьезных основаниях для этого около, 'конечно'. Но так как это - вопрос об интервью, может быть, я неправ (вопросы об интервью должны быть хитрыми, не так ли?).
Синхронизировать тысячу потоков так же просто, как синхронизировать два потока: просто заблокируйте доступ ко всем важным данным.
Теперь синхронизировать тысячу потоков с хорошей производительностью сложнее. Если бы я задавал этот вопрос, я бы поискал ответы, в которых упоминаются «проблема грозного стада», «конфликт блокировок», «масштабируемость реализации блокировки», «предотвращение спин-блокировок» и т. Д.
Я согласен с теми, кто утверждает, что «это зависит от обстоятельств». Если нити идентичны, то такой большой разницы между 2 и 1000 нитками быть не может. Однако, если есть несколько ресурсов, которым требуется взаимоисключающий доступ (синхронизированный в терминах Java), то вероятность взаимоблокировок может увеличиваться с увеличением числа потоков.
Почему синхронизировать 1000 потоков сложнее, чем синхронизировать 2 потока?
Единственный код, который будет добавлен, - это порождение дополнительных потоков.
Вам не нужно было бы добавлять какой-либо код синхронизации (если вы все делали правильно).
Это один из тех вопросов, на который единственный реальный ответ - «это зависит от обстоятельств». В этом случае это зависит от того, что вы с ними делаете.
Сценарий может быть таким же простым, как один фоновый рабочий поток, которого ожидает передний план при отображении индикатора выполнения. Или он может создать 1000 потоков и просто дождаться их завершения, прежде чем делать что-то еще.
В качестве альтернативы, если к разделяемым ресурсам обращаются всего 2 потока, концепции остаются теми же. Вы должны быть очень осторожны с проблемами параллелизма и стратегиями блокировки, будь то 2 или 1000. Независимо от того, сколько потоков более одного, вы не можете гарантировать, что что-то еще не пытается одновременно читать или записывать в тот же ресурс, что и вы. .
Вы можете доказать, что правильно синхронизировать 2 потока на самом деле сложнее, чем сделать это для 1000, потому что, если у вас есть состояние гонки, оно обычно проявляется очень быстро с 1000 потоков, но не только с 2.
Но с другой стороны, синхронизировать 1000 потоков без проблем, связанных с конфликтами блокировок, намного сложнее, чем когда их всего 2.
Настоящий ответ таков: «синхронизировать потоки сложно по-разному, точка»
это так же сложно. Но синхронизация по 2 потокам, скорее всего, будет работать лучше, так как только 2 потока, выполняющих одну блокировку, вместо тысячи, где, скорее всего, будут намного больше накладных расходов из-за заблокированных ресурсов.
Надеюсь, что это помогло
Возьмем задачу «читатель-писатель». С двумя потоками вы можете использовать взаимное исключение, и все готово. При большем количестве потоков вы должны писать нетривиальный код, поскольку в противном случае читатели не могли бы читать одновременно или, что еще хуже, они могли бы голодать писателей.
Однако хороший код синхронизации должен работать для любого количества потоков. В некоторых случаях, например при взаимном исключении, вы можете добавить ключевое слово Java synchronized, и это так же сложно для двух потоков, как и для 1000.
Другими словами, если ваша программа использует только 2 потока, вы можете воспользоваться этим и сделать предположения, что не было бы правдой с большим количеством потоков. Очевидно, это плохая практика, но это возможно.
Думаю, ответ состоит в том, что после синхронизации двух потоков все остальные 998 также будут синхронизированы
В интервью я бы сказал, что "ровно два потока" - это очень полезный частный случай многопоточности. Такие вещи, как голодание и инверсия приоритетов, могут произойти даже с тремя потоками, но только с двумя потоками инверсия приоритетов и голодание никогда не произойдут (ну, голодание может произойти, если поток освободит и снова получит блокировку, не позволив другому потоку начать работу, но с тремя потоками голодание может произойти, даже если блокировки захватываются мгновенно, когда они доступны). Переход от 2 потоков к 3 - это больший скачок, чем переход от 3 к 1000.
Если вы используете такой язык программирования, как Scala, с паттерном проектирования Actors, то вам не нужно ничего синхронизировать. http://www.scala-lang.org/node/242
Другой вариант (в Java) - использовать механизм сравнения и подкачки/сброса http://en.wikipedia.org/wiki/Compare-and-swap, так что вам не придется синхронизировать потоки, поскольку они являются атомарными переменными, которые вы сравниваете и читаете (неблокирующими), и только блокируют/ожидают при записи, что может дать огромный прирост производительности, основанный на вашем решении
.Объекты синхронизируются, а не потоки. Создание синхронизированного метода или блока кода предотвращает одновременное выполнение области несколькими потоками, поэтому не имеет значения, есть ли 2, 1000 или 1000000 потоков.
С точки зрения производительности, если вы ожидаете двойного параллелизма (половину времени выполнения), когда вы удваиваете количество потоков, то любая синхронизированная область будет узким местом с точки зрения производительности, потому что это, по сути, последовательный код, который нельзя распараллеливать.
Это зависит от того, что означает «проще». Сложность конструкции / запорных механизмов примерно такая же.
При этом, я думаю, что 1000 потоковых программ было бы проще отлаживать . Уязвимые гоночные условия имеют более высокую вероятность возникновения и, вероятно, их легче воспроизвести. Состояние гонки в двух потоках может появляться только раз в 5 лет, если луна полная, а вы в отпуске.
У меня два ответа.
Пробежавшись по вашим ответам, я обнаружил несколько интересных хардтов. Я думаю, на собеседовании это важнее, чем ответ: обращение, жесткость.