JavaRush /Java блог /Random UA /Переклад: Топ-50 інтерв'ю питань щодо thread. Частина 1.
KapChook
19 рівень
Volga

Переклад: Топ-50 інтерв'ю питань щодо thread. Частина 1.

Стаття з групи Random UA
Перша частина перекладу оригінальної статті Top 50 Java Thread Interview Questions Answers for Freshers, Experienced Programmers. Друга частина. Примітка: стаття виявилася великою, від чого не міститься в одному топіку. До того ж досить складною, як міг намагався гуглити, але все ж таки. Тому прохання до учасників, які дружать з англійською, одним вічком переглянути оригінал і порівняти з перекладом, раптом що не так зрозумів і неправильно переклав. Заздалегідь дякую. На будь-якому інтерв'ю, для сеньйорів або джуніорів, для досвідчених або початківців, ви зіткнетеся з парою питань про нитки, паралелізм і багатонитність. Фактично ця вбудована підтримка паралелізму є однією з найсильніших переваг Java і допомогла їй досягти популярності і серед підприємців і програмістів. Більшість прибуткових позицій Java розробника вимагають чудового навички багатонитності та досвіду розробки, налагодження та налаштування високопродуктивних додатків з низькою затримкою. Тому це одна з найбільш затребуваних навичок на інтерв'ю. У типовому Java інтерв'ю інтерв'юер повільно починає з базових концептів нитки, ставлячи питання, такі як навіщо потрібні нитки, як їх створити, який спосіб створення краще, успадкуванням від Thread або реалізацією Runnable, а потім повільно переходить до труднощів паралелізму, труднощів, що зустрічаються при розробці паралельних додатків, високорівневим утилітам паралелізму, представленим в JDK 1.5, принципам і дизайн патернам паралельних додатків і класичним проблемам багатонитності. Так як мало просто знати ази багатонитності, ви повинні знати, як справлятися з проблемами паралелізму, такими як взаємне блокування, стан гонки, неузгодженість пам'яті та різні проблеми нитці-безпеки. Ці навички ретельно тестуються, представляючи різні проблеми багатонитності та паралелізму. Багато Java розробники зазвичай просто прочитують питання перед самим інтерв'ю, що не погано, але вам варто розбиратися в цьому. Також накопичення питань та виконання однакових вправ витрачає дуже багато часу, тому я створив цей список. високорівневим утилітам паралелізму, представленим у JDK 1.5, принципам та дизайн патернам паралельних додатків та класичним проблемам багатонитності. Так як мало просто знати ази багатонитності, ви повинні знати, як справлятися з проблемами паралелізму, такими як взаємне блокування, стан гонки, неузгодженість пам'яті та різні проблеми нитці-безпеки. Ці навички ретельно тестуються, представляючи різні проблеми багатонитності та паралелізму. Багато Java розробники зазвичай просто прочитують питання перед самим інтерв'ю, що не погано, але вам варто розбиратися в цьому. Також накопичення питань та виконання однакових вправ витрачає дуже багато часу, тому я створив цей список. високорівневим утилітам паралелізму, представленим у JDK 1.5, принципам та дизайн патернам паралельних додатків та класичним проблемам багатонитності. Так як мало просто знати ази багатонитності, ви повинні знати, як справлятися з проблемами паралелізму, такими як взаємне блокування, стан гонки, неузгодженість пам'яті та різні проблеми нитці-безпеки. Ці навички ретельно тестуються, представляючи різні проблеми багатонитності та паралелізму. Багато Java розробники зазвичай просто прочитують питання перед самим інтерв'ю, що не погано, але вам варто розбиратися в цьому. Також накопичення питань та виконання однакових вправ витрачає дуже багато часу, тому я створив цей список. принципам та дизайн патернам паралельних додатків та класичним проблемам багатонитності. Так як мало просто знати ази багатонитності, ви повинні знати, як справлятися з проблемами паралелізму, такими як взаємне блокування, стан гонки, неузгодженість пам'яті та різні проблеми нитці-безпеки. Ці навички ретельно тестуються, представляючи різні проблеми багатонитності та паралелізму. Багато Java розробники зазвичай просто прочитують питання перед самим інтерв'ю, що не погано, але вам варто розбиратися в цьому. Також накопичення питань та виконання однакових вправ витрачає дуже багато часу, тому я створив цей список. принципам та дизайн патернам паралельних додатків та класичним проблемам багатонитності. Так як мало просто знати ази багатонитності, ви повинні знати, як справлятися з проблемами паралелізму, такими як взаємне блокування, стан гонки, неузгодженість пам'яті та різні проблеми нитці-безпеки. Ці навички ретельно тестуються, представляючи різні проблеми багатонитності та паралелізму. Багато Java розробники зазвичай просто прочитують питання перед самим інтерв'ю, що не погано, але вам варто розбиратися в цьому. Також накопичення питань та виконання однакових вправ витрачає дуже багато часу, тому я створив цей список. неузгодженість пам'яті та різні проблеми нитці-безпеки. Ці навички ретельно тестуються, представляючи різні проблеми багатонитності та паралелізму. Багато Java розробники зазвичай просто прочитують питання перед самим інтерв'ю, що не погано, але вам варто розбиратися в цьому. Також накопичення питань та виконання однакових вправ витрачає дуже багато часу, тому я створив цей список. неузгодженість пам'яті та різні проблеми нитці-безпеки. Ці навички ретельно тестуються, представляючи різні проблеми багатонитності та паралелізму. Багато Java розробники зазвичай просто прочитують питання перед самим інтерв'ю, що не погано, але вам варто розбиратися в цьому. Також накопичення питань та виконання однакових вправ витрачає дуже багато часу, тому я створив цей список.
  1. Що таке нитка у Java?

  2. Нитка – це незалежний шлях виконання. Її мета – скористатися перевагою кількох процесорів, доступних у машині. Використовуючи кілька ниток, можна прискорити завдання, прив'язані до процесору. Наприклад, якщо одній нитці потрібно 100 мілісекунд для виконання роботи, ви можете використовувати 10 ниток, щоб скоротити цю роботу до 10 мілісекунд. Java надає відмінну підтримку багатонитності на рівні мови і це, до того ж, одна з найсильніших її переваг.
  3. Різниця між нитками та процесами в Java?

  4. Нитка - це підмножина процесу, тобто один процес може містити безліч ниток. Два процеси виконуються на різних просторах пам'яті, але всі нитки ділять один простір. Не сплутайте це з пам'яттю стека, яка є різною для кожної нитки і використовується для зберігання локальних даних цієї нитки.
  5. Як створити нитку?

  6. На рівні мови є два способи створення нитки. Об'єкт класу java.lang.Thread є ниткою, але їй потрібне завдання для виконання, яка є об'єктом, що реалізує інтерфейс java.lang.Runnable. Так як клас Thread реалізує інтерфейс Runnable, ви можете перевизначити метод run(), успадкувавши ваш клас від Thread або реалізувавши в ньому інтерфейс Runnable.
  7. Коли використовувати Runnable та коли Thread?

  8. Це доповнення до попереднього питання. Як ми знаємо, нитку можна створити у спадок від класу Thread або реалізувавши інтерфейс Runnable. Виникає питання, який із способів кращий і коли який використовувати? На це питання легко відповісти, якщо ви знаєте, що Java не підтримує множинне спадкування класів, але дозволяє реалізовувати безліч інтерфейсів. Що означає, що краще реалізовувати Runnable, якщо ви хочете успадковуватись від іншого класу.
  9. Різниця між методами start() та run()?

  10. Одне з питань з каверзою з минулого, але воно все ще досить хороше, щоб відрізнити поверхневе розуміння багатонитності в Java. Метод start() використовується запуску нової нитки. Незважаючи на те, що start() викликає метод run() всередині себе, це не те саме, що просто викликати run(). Якщо ви викликаєте run() як звичайний метод, він викликається в тій же нитці і ніяка нова нитка не запуститися, що відбувається, коли ви викликаєте метод start().
  11. Відмінності Runnable та Callable?

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

  14. Хоча обидва ці синхронізатори дозволяють ниткам чекати один одного, головна різниця між ними в тому, що ви не можете знову використовувати CountDownLatch після того, як його лічильник досягне нуля, але ви можете використовувати CyclicBarrier знову, навіть після того, як бар'єр зламається.
  15. Що таке модель пам'яті Java?

  16. Модель пам'яті – це набір правил та вказівок, які дозволяють Java програмам діяти детерміновано серед багатьох архітектур пам'яті, процесора та операційної системи. Це особливо важливо у разі багатонитності. Модель пам'яті надає гарантії того, що зміни, зроблені однією ниткою, будуть помітні для інших, одна з них – відношення happens-before (траплялося раніше). Це ставлення визначає кілька правил, які дозволяють програмістам передбачати та визначати поведінку паралельних програм. Наприклад, happens-before гарантує:
    • Кожна дія в нитці трапляється раніше від будь-якої дії в цій нитці, яка йде в програмному порядку, це також відомо, як правило програмного порядку.
    • Розблокування монітора відбувається раніше кожного наступного блокування того ж самого монітора, також відомо, як правило блокування Монітора.
    • Запис volatile поля відбувається раніше кожного наступного читання цього поля, правило мінливої ​​змінної.
    • Виклик Thread.start() у нитки трапляється раніше, ніж будь-яка інша нитка помічає, що нитка була зупинена, або після успішного Thread.join(), або якщо Thread.isAlive() повертає false, правило Thread.start().
    • Переривання нитки з іншої нитки трапляється раніше, ніж перервана нитка помітить переривання (або від викиду InterruptedException, або від перевірки isInterrupted()), правило переривання нитки.
    • Закінчення конструктора об'єкта відбувається раніше, ніж запуск фіналізатора для цього об'єкта, правило Фіналізатора.
    • Якщо А трапляється раніше В, і В трапляється раніше С, значить А трапляється раніше, що означає happens-before гарантує транзитивність.
  17. Що таке volatile змінна?

  18. Volatile – спеціальний модифікатор, який можна застосовувати лише до атрибутів. У паралельних програмах Java зміни, зроблені різними нитками на атрибутах, не видно для інших за відсутності синхронізатора. Volatile змінна гарантує, що запис буде здійснюватись до наступного читання, що сказано у правилі мінливої ​​змінної у попередньому питанні.
  19. Що таке нитку-безпеку? Чи безпечний клас Vector?

  20. Нитка-безпека – властивість об'єкта або коду, яке гарантує, що при виконанні або використанні кількома нитками, код поводитиметься, як передбачається. Наприклад нитку-безпечний лічильник не пропустить жоден рахунок, якщо той самий екземпляр лічильника використовується серед кількох ниток. Очевидно, можна розділити класи колекцій на дві категорії, нитко-безпечні та не-нитко-безпечні. Vector нитко-безпечний і досягає цього синхронізацією методів, які змінюють стан Vector'a, з іншого боку його колега ArrayList не-нитко-безпечний.
  21. Що таке стан гонки (Race Condition)?

  22. Стан гонки - причина важковловимих багів. Як сказано в самій назві, стан гонки виникає через гонку між кількома нитками, якщо нитка, яка повинна виконатися першою, програла гонку і виконується друга, поведінка коду змінюється, через що виникають недетерменовані баги. Це одні з найскладніших до відлову та відтворення багів, через безладну природу гонок між нитками. Приклад стану гонки – безладне виконання.
  23. Як зупинити нитку?

  24. Я завжди говорив, що Java надає багаті API для всього, але за іронією долі не надає зручних способів зупинки нитки. У JDK 1.0 було кілька керуючих методів, наприклад stop(), suspend() і resume(), які були помічені як deprecated в майбутніх релізах через потенційні загрози взаємного блокування, з тих пір розробники Java API не зробабо спроб представити стійкий, нитці -безпечний та елегантний спосіб зупинки ниток. Програмісти в основному покладаються на факт того, що нитка зупиняється сама, коли закінчує виконувати методи run() або call(). Для зупинки вручну, програмісти користуються перевагою volatile boolean змінної та перевіряють її значення в кожній ітерації, якщо в методі run() є цикли, або переривають нитки методом interrupt() для раптового скасування завдань.
  25. Що відбувається, коли у нитці з'являється виняток?

  26. Це одне з добрих питань із каверзою. Простими словами, якщо виняток не спіймано – нитка мерта, якщо встановлений обробник непойманих винятків, він отримає колбек. Thread.UncaughtExceptionHandler – інтерфейс, визначений як вкладений інтерфейс для оброблювачів, що викликаються, коли нитка раптово зупиняється через непойманий виняток. Коли нитка збирається зупиниться через непойманий виняток, JVM перевірить її на наявність UncaughtExceptionHandler, використовуючи Thread.getUncaughtExceptionHandler(), і викличе у обробника метод uncaughtException(), передавши нитку та виняток у вигляді аргументів.
  27. Як поділитись даними між двома нитками?

  28. Ви можете ділитися даними між нитками, використовуючи спільний об'єкт або паралельні структури даних, як BlockingQueue.
  29. Відмінності між notify і notifyAll?

  30. Це ще одне з питань з каверзою, оскільки за одним монітором можуть спостерігати кілька ниток, Java API розробники надають метод для повідомлення про зміну його стану тільки однієї або відразу всіх ниток, але вони надають лише половину реалізації. У методу notify() не реалізовано спосіб вибору певної нитки, тому він корисний тільки коли ви точно знаєте, що всього одна нитка чекає. З іншого боку, notifyAll() повідомляє всі нитки і дозволяє їм поборотися за монітор, що гарантує, що принаймні одна нитка просунеться далі.
  31. Чому wait, notify і notifyAll не в класі Thread?

  32. Це питання, що стосується дизайну, який перевіряє, що кандидат думає про існуючі системи або думав він колись про щось схоже, але виглядає недоречно спочатку. Щоб відповісти на це питання, вам потрібно надати кілька причин, чому ці методи зручніше реалізовувати в класі Object і чому не в Thread. Перша очевидна причина – Java підтримує lock лише на рівні об'єктів, а чи не лише на рівні ниток. Будь-який об'єкт має lock, який отримує нитку. І якщо нитки потрібно чекати на певний lock, є сенс у тому, щоб викликати wait() на об'єкт, ніж на цю нитку. Якби wait() був оголошений у класі Thread, було б не ясно, який lock нитка чекає. Коротко, оскільки wait, notify і notifyAll працюють на рівні lock, зручніше оголосити їх у класі Object, тому що lock відноситься до об'єкта.
  33. Що таке ThreadLocal змінна?

  34. ThreadLocal змінні – спеціальний вид змінних, доступних програмісту Java. Так само, як для станів є змінні стани, для ниток є ThreadLocal змінні. Це непоганий спосіб досягти нитці-безпеки для витратних-для-створення об'єктів, наприклад, ви можете зробити SimpleDateFormat нитці-безпечним, використовуючи ThreadLocal. Так як це затратний клас, його небажано використовувати в локальній області, яка потребує окремих екземплярів на кожний виклик. Надаючи кожній нитці її власну копію, ви вбиваєте двох зайців. По-перше, ви зменшуєте кількість екземплярів витратних об'єктів, використовуючи по новій фіксовану кількість екземплярів, і по-друге, ви досягаєте нитки-безпеки, без втрат синхронізації та незмінності. Ще один хороший приклад локальної змінної у нитки - клас ThreadLocalRandom,
  35. Що таке FutureTask?

  36. FutureTask являє собою асинхронне обчислення, що скасовується в паралельному Java додатку. Цей клас надає базову реалізацію Future, з методами для запуску та зупинення обчислення, методами для запиту стану обчислення та отримання результатів. Результат може бути отриманий тільки тоді, коли обчислення завершено, метод отримання буде заблоковано, якщо обчислення ще не завершено. Об'єкти FutureTask можуть бути використані для обгортки об'єктів Callable та Runnable. Так як FutureTask реалізує Runnable, його можна передати Executor'у на виконання.
  37. Відмінність між interrupted і isinterrupted?

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

  40. Основна причина виклику wait і notify зі статичного блоку або методу в тому, що Java API обов'язково вимагає цього. Якщо ви викликаєте їх не з синхронізованого блоку, код викине IllegalMonitorStateException. Більш хитра причина у тому, щоб уникнути стану гонки між викликами wait та notify.
  41. Чому ви повинні перевіряти стан очікування у циклі?

  42. Існує можливість того, що нитка, що очікує, отримає помилкові попередження і помилкові виклики пробудження, якщо вона не перевірить стан очікування в циклі, вона просто вийде, навіть якщо стан не досягнуто. Коли нитка, що очікує, прокидається, вона не думає про те, що стан, який вона очікувала, може все ще залишатися в силі. Воно могло бути дійсно в минулому, але потім було змінено після виклику методу notify() і перед тим, як нитка прокинулася. Тому завжди краще викликати wait() із циклу.
  43. Відмінності між synchronized та concurrent колекціями?

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

  46. Чому це питання присутнє у питаннях про багато-нітиєвість? Тому що стек – ділянка пам'яті, тісно пов'язана з нитками. Кожна нитка має свій стек, який зберігає локальні змінні, параметри методів і стек викликів. Змінна, що зберігається в стеку однієї нитки, не видно для іншої. З іншого боку, купа – спільна ділянка пам'яті, яка ділиться між усіма нитками. Об'єкти, неважливо локальні чи іншого рівня, створюються у купі. Для поліпшення продуктивності, нитка зазвичай кешує значення з купи у свій стек, тут виповзають volatile змінні. Volatile показує ниткам те що, що змінну необхідно читати з головної пам'яті.
  47. Що таке пул ниток?

  48. Створення нитки витратно у плані часу та ресурсів. Якщо ви створюєте нитку під час обробки запиту, це сповільнить час відгуку, процес може створити тільки обмежену кількість ниток. Щоб уникнути цих проблем, під час запуску програми створюється пул ниток і нитки повторно використовуються для обробки запитів. Цей пул ниток називається «thread pool», а нитки у ньому – робоча нитка. Починаючи з Java 1.5 Java API надає фреймворк Executor, який дозволяє вам створювати різні пули ниток, наприклад single thread pool, який обробляє тільки одне завдання за одиницю часу, fixed thread pool, пул з фіксованою кількістю ниток, і cached thread pool, пул, що розширюється, придатний додатків з безліччю недовгих завдань.
  49. Як вирішити проблему Producer Consumer?

  50. Більшість ниткових проблем, які ви вирішуєте в реальності, з категорії патерну Producer Consumer, в якому одна нитка породжує завдання, а друга поглинає її. Вам потрібно знати, як побудувати внутрішні взаємодії ниток для вирішення цієї проблеми. На низькому рівні ви можете скористатися методами wait та notify, а на високому рівні ви можете скористатися перевагами Semaphore або BlockingQueue
  51. Як уникнути взаємного блокування (deadlock)?

  52. Переклад: Топ-50 інтерв'ю питань щодо ниток.  Частина 1. - 1 Deadlock – стан, у якому нитка чекає, поки друга нитка зробить якесь дію, а друга, у той час, чекає того ж від першої. Це дуже серйозна проблема, через яку ваша програма зависає і не робить того, навіщо вона призначена. Deadlock відбувається, коли досягаються ці 4 стани:
    • Взаємний виняток: принаймні один ресурс має бути зайнятий у режимі неподільності. Тільки один процес може використовувати ресурс у будь-який момент часу.
    • Утримання та очікування: процес утримує як мінімум один ресурс та запитує додаткові ресурси, які утримуються іншими процесами.
    • Немає перед-очищення: операційна система не перепризначає ресурси, якщо вони вже зайняті, вони повинні віддаватися добровільно, що утримує процес.
    • Циклічне очікування: процес чекає на звільнення ресурсів іншим процесом, який у свою чергу чекає на звільнення ресурсів першим процесом.
    Найпростіший спосіб уникнути взаємного блокування – не допускати циклічного очікування, цього можна досягти, отримуючи lock'и у певному порядку та звільняючи їх у зворотному порядку.
  53. Відмінності між livelock та deadlock?

  54. Livelock схожий з deadlock, тільки в livelock стан ниток або залучених процесів постійно змінюються в залежності один від одного. Livelock – особливий випадок нестачі ресурсів. Реальний приклад livelock'а – коли дві людини зустрічаються у вузькому коридорі і кожен, намагаючись бути ввічливим, відходить убік, і так вони нескінченно рухаються з боку убік.
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ