JavaRush /Java Blog /Random-JA /翻訳: スレッドごとのインタビューの質問トップ 50。パート1。
KapChook
レベル 19
Volga

翻訳: スレッドごとのインタビューの質問トップ 50。パート1。

Random-JA グループに公開済み
オリジナル記事Top 50 Java Thread Interview question Answers for Freshers, Experienced Programmers の翻訳の最初の部分です。 第二部。 注:この記事は大きくなったため、1 つのトピックに収まりませんでした。それに、かなり複雑なので、頑張ってグーグルで調べてみましたが、それでも。そのため、英語が流暢な参加者には、誤解や誤訳に備えて、原文を見て翻訳と比較してもらいます。よろしくお願いします。 先輩でも後輩でも、経験者でも初心者でも、どの面接でも、スレッド、並列処理、マルチスレッドに関するいくつかの質問に直面するでしょう。実際、この組み込みの並行性サポートは Java の最大の強みの 1 つであり、起業家やプログラマーの間で Java が人気を博すのに役立ってきました。有利な Java 開発者のポジションのほとんどは、優れたマルチスレッド スキルと、高性能で低遅延のアプリケーションの開発、デバッグ、チューニングの経験を必要とします。したがって、面接で最も求められるスキルの1つです。典型的な Java 面接では、面接官はゆっくりとスレッドの基本概念から始め、スレッドが必要な理由、スレッドの作成方法、どの作成方法がより良いか、Thread から継承するか Runnable を実装するかなどの質問をし、その後ゆっくりと話を進めます。並行性の難しさ、並列アプリケーションの開発で遭遇する困難、JDK 1.5 で導入された高レベルの並行性ユーティリティ、並列アプリケーションの原理と設計パターン、および古典的なマルチスレッド問題について説明します。マルチスレッドの基本を理解するだけでは十分ではないため、デッドロック、競合状態、メモリの不整合、さまざまなスレッドの安全性の問題などの同時実行の問題に対処する方法を知っておく必要があります。これらのスキルは徹底的にテストされ、さまざまなマルチスレッドと同時実行の課題が提示されます。多くの Java 開発者は通常、面接自体の前に質問を読むだけで、それは悪いことではありませんが、これを理解する必要があります。また、質問をためたり、同じ演習をしたりするのは非常に時間の無駄なので、このリストを作成しました。
  1. Java のスレッドとは何ですか?

  2. スレッドは独立した実行パスです。その目標は、マシンで利用可能な複数のプロセッサを活用することです。複数のスレッドを使用すると、CPU 依存のタスクを高速化できます。たとえば、1 つのスレッドがジョブを完了するのに 100 ミリ秒かかる場合、10 個のスレッドを使用すると、そのジョブを 10 ミリ秒に短縮できます。Java は言語レベルでマルチスレッドの優れたサポートを提供しており、これが Java の最も強力な利点の 1 つです。
  3. Javaのスレッドとプロセスの違いは何ですか?

  4. Нить – это подмножество процесса, другими словами один процесс может содержать множество нитей. Два процесса исполняются на различных пространствах памяти, но все нити делят одно пространство. Не спутайте это с памятью стека, которая различная для каждой нити и используется для хранения локальных данных этой нити.
  5. Как создать нить?

  6. На уровне языка есть два способа создания нити. Объект класса java.lang.Thread представляет собой нить, но ей требуется задача для исполнения, которая является an objectом, реализующим интерфейс java.lang.Runnable. Так How класс Thread реализует интерфейс Runnable, вы можете переопределить метод run() унаследовав ваш класс от Thread or реализовав в нём интерфейс Runnable.
  7. Когда использовать Runnable и когда Thread?

  8. Это дополнение к предудыщему вопросу. Как мы знаем, нить можно создать унаследовавшись от класса Thread or реализовав интерфейс Runnable. Возникает вопрос, который из способов лучше и когда Howой использовать? На этот вопрос легко ответь, если вы знаете, что Java не поддерживает множественное наследование классов, но позволяет реализовывать множество интерфейсов. What означает, что лучше реализовывать Runnable, если вы хотите унаследоваться от другого класса.
  9. Difference между методами start() и run()?

  10. Один из вопросов с подвохом из прошлого, но он всё ещё достаточно хорош, чтобы отличить поверхностное понимание многонитиевости в Java. Метод start() используется для запуска новой нити. Несмотря на то, что start() вызывает метод run() внутри себя, это не то же самое, что просто вызвать run(). Если вы вызываете run() How обычный метод, он вызывается в той же нити и ниHowая новая нить не запуститься, что происходит, когда вы вызываете метод start().
  11. Различия Runnable и Callable?

  12. Оба интерфейса представляют задачи, которые предназначены для выполнения в отдельных нитях. Runnable существует ещё с JDK 1.0, а Callable был добавлен в JDK 1.5. Главное их различие заключается в том, что метод call() у Callable может возвращать значения и выбрасывать исключения, что невозможно в методе run() у Runnable. Callable возвращает an object Future, который может содержать результат вычислений.
  13. Различия между CyclicBarrier и CountDownLatch?

  14. Хоть оба эти синхронизаторы позволяют нитям дожидаться друг друга, главное различие между ними в том, что вы не можете заново использовать CountDownLatch после того, How его счётчик достигнет нуля, но вы можете использовать CyclicBarrier снова, даже после того, How барьер сломается.
  15. What такое модель памяти Java?

  16. Модель памяти – это набор правил и указаний, которые позволяют Java программам действовать детерминировано среди множества архитектур памяти, процессора и операционной системы. Это особенно важно в случае многонитиевости. Модель памяти предоставляет гарантии того, что изменения, произведённые одной нитью, будут видны для других, одна из них – отношение happens-before (случалось ранее). Это отношение определяет несколько правил, которые позволяют программистам предвидеть и определять поведение параллельных программ. Например happens-before гарантирует:
    • Каждое действие в нити случается раньше любого действия в этой нити, которое следует в программном порядке, это также известно, How правило программного порядка.
    • Разблокировка монитора случается раньше каждой последующей блокировки того же самого монитора, также известно, How правило блокировки Монитора.
    • Запись volatile поля случается раньше каждого последующего чтения этого поля, правило изменчивой переменной.
    • Вызов Thread.start() в нити случается раньше, чем любая другая нить замечает, что нить была остановлена, либо после удачного Thread.join(), либо если Thread.isAlive() возвращает false, правило Thread.start().
    • Прерывание нити из другой нити случается раньше, чем прерванная нить заметит прерывание (либо от выброса InterruptedException, либо от проверки isInterrupted()), правило прерывания нити.
    • Окончание конструктора an object случается раньше, чем запуск финализатора для этого an object, правило Финализатора.
    • Если А случается раньше В, и В случается раньше С, значит А случается раньше С, что значит happens-before гарантирует транзитивность.
  17. What такое volatile переменная?

  18. Volatile – специальный модификатор, который может применяться только к атрибутам. В параллельных Java программах изменения, произведённые различными нитями на атрибутах, не видны для остальных при отсутствии синхронизатора. Volatile переменная гарантирует, что запись будет осуществляться до последующего чтения, что сказано в правиле изменчивой переменной в предыдущем вопросе.
  19. What такое ните-безопасность? Безопасный ли класс Vector?

  20. Ните-безопасность – свойвство an object or codeа, которое гарантирует, что при исполнении or использовании несколькими нитями, code будет вести себя, How предполагается. Например ните-безопасный счётчик не пропустит ни один счёт, если тот же экземпляр счётчика используется среди нескольких нитей. Очевидно, можно разделить классы коллекций на две категории, ните-безопасные и не-ните-безопасные. Vector ните-безопасен и достигает этого синхронизацией методов, которые изменяют состояние Vector’a, с другой стороны его коллега ArrayList не-ните-безопасен.
  21. What такое состояние гонки (race condition)?

  22. Состояние гонки – причина трудноуловимых багов. Как сказано в самом названии, состояние гонки возникает из-за гонки между несколькими нитями, если нить, которая должна исполнятся первой, проиграла гонку и исполняется вторая, поведение codeа изменяется, из-за чего возникают недетерменированные баги. Это одни из сложнейших к отлавливанию и воспроизведению багов, из-за беспорядочной природы гонок между нитями. Пример состояния гонки – беспорядочное исполнение.
  23. Как остановить нить?

  24. Я всегда говорил, что Java предоставляет богатые API для всего, но, по иронии судьбы, не предоставляет удобных способов остановки нити. В JDK 1.0 было несколько управляющих методов, например stop(), suspend() и resume(), которые были помечены How deprecated в будущих релизах из-за потенциальных угроз взаимной блокировки, с тех пор разработчики Java API не предприняли попыток представить стойкий, ните-безопасный и элегантный способ остановки нитей. Программисты в основном полагаются на факт того, что нить останавливается сама, How только заканчивает выполнять методы run() or call(). Для остановки вручную, программисты пользуются преимуществом volatile boolean переменной и проверяют её meaning в каждой итерации, если в методе run() есть циклы, or прерывают нити методом interrupt() для внезапной отмены заданий.
  25. What происходит, когда в нити появляется исключение?

  26. Это один из хороших вопросов с подвохом. Простыми словами, если исключение не поймано – нить мерта, если установлен обработчик непойманных исключений, он получит колбек. Thread.UncaughtExceptionHandler – интерфейс, определённый How вложенный интерфейс для обработчиков, вызываемых, когда нить внезапно останавливается из-за непойманного исключения. Когда нить собирается остановится из-за непойманного исключения, JVM проверит её на наличие UncaughtExceptionHandler, используя Thread.getUncaughtExceptionHandler(), и вызовет у обработчика метод uncaughtException(), передав нить и исключение в виде аргументов.
  27. Как поделиться данными между двумя нитями?

  28. Вы можете делиться данным между нитями, используя общий an object or параллельные структуры данных, типа BlockingQueue.
  29. Различия между notify и notifyAll?

  30. Это ещё один из вопросов с подвохом, так How за одним монитором могут наблюдать несколько нитей, Java API разработчики предоставляют метод для уведомления об изменении его состояния только одной or сразу всех нитей, но они предоставляют только половину реализации. У метода notify() не реализован способ выбора определённой нити, поэтому он полезен только когда вы точно знаете, что всего одна нить ожидает. С другой стороны, notifyAll() уведомляет все нити и позволяет им побороться за монитор, что гарантирует, что по крайней мере одна нить продвинется дальше.
  31. Почему wait, notify и notifyAll не в классе Thread?

  32. Это вопрос, относящийся к дизайну, который проверяет, что кандидат думает о существующих системах or думал ли он когда-либо о чём-то схожем, но выглядящем неуместно поначалу. Whatбы ответить на этот вопрос, вам нужно предоставить несколько причин, почему эти методы удобнее реализовывать в классе Object, и почему не в классе Thread. Первая очевидная причина – Java поддерживает lock на уровне an objectов, а не на уровне нитей. Любой an object имеет lock, который получает нить. И если нити нужно ждать определённый lock, есть смысл в том, чтобы вызвать wait() на an object, чем на эту нить. Если бы wait() был объявлен в классе Thread, было бы не ясно, Howой lock нить ждёт. Вкратце, так How wait, notify и notifyAll работают на уровне lock, удобнее объявить их в классе Object, потому что lock относится к an objectу.
  33. What такое ThreadLocal переменная?

  34. ThreadLocal переменные – специальный вид переменных, доступных Java программисту. Так же, How для состояний есть переменная состояния, для нитей есть ThreadLocal переменные. Это неплохой способ достичь ните-безопасности для затратных-для-создания an objectов, например вы можете сделать SimpleDateFormat ните-безопасным, используя ThreadLocal. Так How это затратный класс, его нежелательно использовать в локальной области, которая требует отдельных экземпляров на каждый вызов. Предоставляя каждой нити её собственную копию, вы убиваете двух зайцев. Во-первых, вы уменьшаете количество экземпляров затратных an objectов, используя по новой фиксированное количество экземпляров, и во-вторых, вы достигаете ните-безопасности, без потерь синхронизации и неизменяемости. Ещё один хороший пример локальной переменной у нити – класс ThreadLocalRandom, который уменьшает количество экземпляров затратных-для-создания an objectов Random в много-нитиевой среде.
  35. What такое FutureTask?

  36. FutureTask представляет собой отменяемое асинхронное вычисление в параллельном Java приложении. Этот класс предоставляет базовую реализацию Future, с методами для запуска и остановки вычисления, методами для requestа состояния вычисления и извлечения результатов. Результат может быть получен только когда вычисление завершено, метод получения будет заблокирован, если вычисление ещё не завершено. Объекты FutureTask могут быть использованы для обёртки an objectов Callable и Runnable. Так How FutureTask реализует Runnable, его можно передать Executor’у на выполнение.
  37. Различие между interrupted и isInterrupted?

  38. Основное различие между interrupted() и isInterrupted() в том, что первый сбрасывает статус прерывания, а второй нет. Механизм прерывания в Java реализован с использованием внутреннего флага, известного How статус прерывания. Прерывание нити вызовом Thread.interrupt() устанавливает этот флаг. Когда прерванная нить проверяет статус прерывания, вызывая статический метод Thread.interrupted(), статус прерывания сбрасывается. Нестатический метод isInterrupted(), который используется нитью для проверки статуса прерывания у другой нити, не изменяет флаг прерывания. Условно, любой метод, который завершается, выкинув InterruptedException сбрасывает при этом флаг прерывания. Однако, всегда существует возможность того, что флаг тут же снова установится, если другая нить вызовет interrupt().
  39. Почему методы wait и notify вызываются в синхронизированном блоке?

  40. Основная причина вызова wait и notify из статического блока or метода в том, что Java API обязательно требует этого. Если вы вызовете их не из синхронизированного блока, ваш code выбросит IllegalMonitorStateException. Более хитрая причина в том, чтобы избежать состояния гонки между вызовами wait и notify.
  41. Почему вы должны проверять состояние ожидания в цикле?

  42. Существует возможность того, что ожидающая нить получит ложные предупреждения и ложные вызовы пробуждения, если она не проверит состояние ожидания в цикле, она просто выйдет, даже если состояние не достигнуто. Когда ожидающая нить пробуждается, она не думает о том, что состояние, которое она ожидала, может все ещё оставаться в силе. Оно могло быть действительно в прошлом, но потом быть изменено после вызова метода notify() и перед тем How нить пробудилась. Поэтому всегда лучше вызывать wait() из цикла.
  43. Различия между synchronized и concurrent коллекциями?

  44. Хоть обе synchronized и concurrent коллекции предоставляют ните-безопасные коллекции, последняя является более масштабируемой. До Java 1.5 программистам были доступны только synchronized коллекции, которые становorсь источником раздора, когда несколько нитей обращались к ним одновременно, что затрудняло масштабирование системы. Java 5 представила concurrent коллекции, например ConcurrentHashMap, которые не только предоставляют ните-безопасность, но также улучшают масштабируемость, используя современные техники, такие How lock stripping и partitioning internal table.
  45. Различия между Стеком и Кучей?

  46. Почему этот вопрос присутствует в вопросах о много-нитиевости? Потому что стек – участок памяти, тесно связанный с нитями. У каждой нити есть свой стек, которые хранит локальные переменные, параметры методов и стек вызовов. Переменная, хранящаяся в стеке одной нити, не видна для другой. С другой стороны, куча – общий участок памяти, который делится между всеми нитями. Объекты, неважно локальные or любого другого уровня, создаются в куче. Для улучшения производительности, нить обычно кэширует значения из кучи в свой стек, тут-то выползают volatile переменные. Volatile указывает нитям на то, что переменную нужно читать из главной памяти.
  47. What такое пул нитей?

  48. Creation нити затратно в плане времени и ресурсов. Если вы создаёте нить во время обработки requestа, это замедлит время отклика, также процесс может создать только ограниченное число нитей. Whatбы избежать этих проблем, во время запуска applications создаётся пул нитей и нити повторно используются для обработки requestов. Этот пул нитей называется «thread pool», а нити в нём – рабочая нить. Начиная с Java 1.5 Java API предоставляет фреймворк Executor, который позволяет вам создавать различные пулы нитей, например single thread pool, который обрабатывает только одно задание за единицу времени, fixed thread pool, пул с фиксированным количеством нитей, и cached thread pool, расширяемый пул, подходящий для приложений с множеством недолгих заданий.
  49. Как решить Producer Consumer проблему?

  50. Большинство нитиевых проблем, которые вы решаете в реальности, из категории паттерна Producer Consumer, в котором одна нить порождает задачу, а вторая поглощает её. Вам нужно знать, How построить внутренние взаимодействия нитей, для решения этой проблемы. На низком уровне вы можете воспользоваться методами wait и notify, а на высоком уровне вы можете воспользоваться преимуществами Semaphore or BlockingQueue
  51. Как избежать взаимной блокировки (deadlock)?

  52. 翻訳: スレッドごとのインタビューの質問トップ 50。 パート 1. - 1 Deadlock – состояние, в котором нить ждёт, пока вторая нить совершит Howое-либо действие, а вторая, в это же время, ждёт того же от первой. Это очень серьёзная проблема, из-за которой ваша программа зависает и не делает того, для чего она предназначена. Deadlock происходит, когда достигаются эти 4 состояния:
    • Взаимное исключение: по крайней мере один ресурс должен быть занят в режиме неделимости. Только один процесс может использовать ресурс в любой данный момент времени.
    • Удержание и ожидание: процесс удерживает How минимум один ресурс и запрашивает дополнительных ресурсов, которые удерживаются другими процессами.
    • Нет пред-очистке: операционная система не переназначивает ресурсы, если они уже заняты, они должны отдаваться удерживающим процессом добровольно.
    • Цикличное ожидание: процесс ждёт освобождения ресурсов другим процессом, который в свою очередь ждёт освобождения ресурсов первым процессом.
    デッドロックを回避する最も簡単な方法は、ループでの待機を回避することです。これは、特定の順序でロックを取得し、逆の順序でロックを解放することで実現できます。
  53. ライブロックとデッドロックの違いは?

  54. ライブロックはデッドロックに似ていますが、ライブロックでは関係するスレッドまたはプロセスの状態が相互に依存して常に変化します。ライブロックはリソース不足の特殊なケースです。ライブロックの実際の例は、狭い廊下で 2 人の人が出会い、それぞれが礼儀正しくしようとして脇に下がり、延々と左右に移動する場合です。
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION