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

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

Стаття з групи Random UA
Друга частина перекладу оригінальної статті Top 50 Java Thread Interview Questions Answers for Freshers, Experienced Programmers. Перша частина.
  1. Як перевірити, чи утримує нитку lock?

  2. Я і не підозрював, що можна перевіряти, чи утримує нитку lock в даний момент, доки не зіткнувся з цим питанням в одному телефонному інтерв'ю. У java.lang.Thread є метод holdsLock(), він повертає true, тоді і тільки тоді, коли нитка поточна утримує монітор у певного об'єкта.
  3. Як отримати дамп нитки?

  4. Дамп нитки дозволяє дізнатися, чим нитка займається зараз. Існує кілька способів одержання дампи нитки, що залежать від операційної системи. У Windows можна використовувати комбінацію ctrl + Break, в Linux – команду kill -3. Також ви можете скористатися утилітою jstack, вона оперує над id процесом, який ви можете дізнатися за допомогою іншої утиліти jps.
  5. Який параметр JVM використовується для контролю розміру стека нитки?

  6. Це один з простих, -Xss параметр використовується для контролю розміру стека нитки в Java.
  7. Відмінності між synchronized та ReentrantLock?

  8. Були часи, коли єдиний спосіб досягнення взаємного виключення був через ключове слово synchronized, але він має кілька недоліків, наприклад, не можна розширити lock за межами методу або блоку коду і т.д. Java 5 вирішує цю проблему, надаючи більш витончений контроль через інтерфейс Lock. ReentrantLock – поширена реалізація Lock, яка надає Lock з такою самою базовою поведінкою та семантикою, як у неявного монітора, що досягається використанням синхронізованих методів, але з розширеними можливостями.
  9. Дано 3 нитки Т1, Т2 і Т3? Як реалізувати послідовність Т1, Т2, Т3?

  10. Послідовності можна досягти багатьма способами, але ви можете просто скористатися методом join(), щоб запустити нитку, коли інша закінчить виконання. Для реалізації заданої послідовності, вам потрібно запустити останню нитку першої, а потім викликати метод join() у зворотному порядку, тобто Т3 викликає Т2.join, а Т2 викликає Т1.join, таким чином Т1 закінчить виконання першої, а Т3 останньої.
  11. Що робить метод yield?

  12. Метод yield – один із способів попросити нитку поступитися процесором, щоб інша могла виконатися. Це статичний метод і він тільки гарантує, що нитка поступиться процесор, але не вирішує, до якої нитки перейде виконання.
  13. Який рівень паралелізму ConcurrentHashMap?

  14. ConcurrentHashMap досягає своєї масштабованості та нитки-безпеки, розбиваючи дійсну map на секції. Цей поділ досягається використанням рівня паралелізму. Це опціональний параметр конструктора ConcurrentHashMap та його значення за замовчуванням 16.
  15. Що таке Semaphore?

  16. Semaphore – це новий тип синхронізатора. Це семафор із лічильником. Концептуально, семафор керує набором дозволів. Кожен acquire() блокується, якщо необхідно, до того, як дозвіл доступний, потім отримує його. Кожен release() додає дозвіл, потенційно звільняючи блокуючий одержувач (acquirer). Однак при цьому не використовуються фактичні об'єкти дозволів; Semaphore просто зберігає кількість доступних і діє відповідно. Semaphore використовується для захисту дорогих ресурсів, які доступні в обмеженій кількості, наприклад, підключення до бази даних в пулі.
  17. Що буде, якщо черга пула ниток вже заповнена, а ви подасте завдання?

  18. Якщо черга пула ниток заповнилася, то це завдання буде «відхилено». Метод submit() у ThreadPoolExecutor'а викидає RejectedExecutionException, після чого викликається RejectedExecutionHandler.
  19. Відмінності між методами submit() і execute() у пулу ниток?

  20. Обидва методи є способами подачі задачі в пул ниток, але між ними є невелика різниця. Execute(Runnable command) визначений в інтерфейсі Executor і виконує подане завдання у майбутньому, але, що важливіше, нічого не повертає. З іншого боку submit() – перевантажений метод, він може приймати завдання типів Runnable і Callable і може повертати об'єкт Future, який можна використовувати для скасування виконання та очікування результату обчислень. Цей метод визначений в інтерфейсі ExecutorService, який успадковується від інтерфейсу Executor, і кожен клас пула ниток, наприклад ThreadPoolExecutor або ScheduledThreadPoolExecutor, успадковує ці методи.
  21. Що таке метод блокування?

  22. Блокуючий метод – метод, який блокується, доки не виконається завдання, наприклад, метод accept() у ServerSocket блокується в очікуванні підключення клієнта. Тут блокування означає, що контроль не повернеться до методу, що викликає, до тих пір, поки не виконається завдання. З іншого боку, існують асинхронні методи, що не блокуються, які завершуються до виконання завдання.
  23. Ніте-безпечний чи Swing?

  24. Простіше кажучи, ні, Swing не нитку безпечний, але вам потрібно пояснити, що ви цим маєте на увазі, навіть якщо інтерв'юер не запитав про це. Коли ми говоримо, що Swing не нитці безпечний, ми зазвичай посилаємося на те, що це компонент, який не може бути модифікований декількома нитками. Всі зміни GUI компонентів повинні бути зроблені в нитки AWT, і Swing надає синхронні та асинхронні методи для планування таких змін.
  25. Відмінності між ринкомАндWait і артеріальномузаходу?

  26. Це два методи Swing API, які дозволяють розробникам оновлювати GUI компоненти з ниток, а не з нитки Диспетчера подій. InvokeAndWait() синхронно оновлює GUI компонент, наприклад смужка прогресу, кожного разу, коли досягнуто прогресу, смужка повинна бути оновлена, щоб відобразити зміни. Якщо прогрес відстежується в іншій нитці, він повинен викликати invokeAndWait() для призначення оновлення цього компонента ниткою Диспетчера подій. А invokeLater() – асинхронний виклик оновлення компонентів.
  27. Які методи Swing API нитко-безпечні?

  28. Це питання знову про Swing та нитку-безпеку, хоч компоненти Swing не нитку-безпечні, існують методи, які можна безпечно викликати з кількох ниток. Я знаю, що repaint() і revalidate() нитці-безпечні, але є й інші методи на різних Swing компонентах, наприклад setText() у JTextComponent, методи insert() та append() у класі JTextArea.
  29. Як створити незмінні об'єкти?

  30. Це питання може здатися таким, що не має нічого спільного з багатонітиєвістю і паралелізмом, але воно має. Незмінність допомагає спростити і так складний паралельний код. Незмінний об'єкт дуже дорогий для розробників, оскільки він може поширюватися без синхронізації. На жаль, у Java немає анотації @Immutable, яка зробить ваш об'єкт незмінним, для цього розробникам потрібно попітніти. Щоб створити незмінний об'єкт, потрібно дотримуватися основ: ініціалізація в конструкторі, відсутність сеттерів, відсутність витоку посилання, зберігати окремо копії змінних об'єктів.
  31. Що таке ReadWriteLock?

  32. В цілому, ReadWriteLock - це результат техніки аналізу lock'а для покращення продуктивності паралельних додатків. Це інтерфейс, який був доданий до Java 5. Він оперує парою пов'язаних lock'ів, один для операцій читання, один для запису. Читаючий lock може утримуватися одночасно кількома нитками, що читають, до тих пір поки не буде записуючих. Записуючий lock ексклюзивний. Якщо хочете, ви можете реалізувати інтерфейс з вашим набором правил, або ви можете використовувати ReentrantReadWriteLock, який підтримує максимум 65535 рекурсивних записуючих lock'ів та 65535 читаючих lock'ів.
  33. Що таке busy spin?

  34. Busy Spin – це техніка, яку програмісти використовують, щоб змусити нитку чекати за певної умови. На відміну від традиційних методів, wait(), sleep() або yield(), які мають на увазі поступання контролю над процесором, цей метод не поступається процесором, натомість він просто виконує порожній цикл. Навіщо комусь це робити? Щоб зберегти кеш-процесор. У багатоядерних системах існує можливість, що призупинена нитка продовжить своє виконання на іншому ядрі, що означає перебудову кешу. Щоб уникнути витратної перебудови, програміст вважає за краще чекати менше, використовуючи busy spin.
  35. Відмінності між volatile та atomic змінними?

  36. Це досить цікаве питання, спочатку volatile та atomic змінні виглядають дуже схоже, але все ж таки вони різні. Volatile змінна надає happens-before гарантію, що запис буде вироблено до будь-якого наступного запису, він не гарантує атомарності. Наприклад, операція count++ не стане атомарною просто тому, що count оголошена volatile. З іншого боку class AtomicInteger надає атомарний метод виконання таких складних операцій атомарно, наприклад getAndIncrement() – атомарна заміна оператора инкремента, можна використовувати, щоб атомарно збільшити поточне значення однією. Також існують атомарні версії та інших типів даних.
  37. Що трапиться, якщо нитка викине Виняток у синхронізованому блоці?

  38. Це ще одне питання з каверзою для звичайних Java програмістів. Не важливо, як ви виходите із синхронізованого блоку, нормально, закінчивши виконання, або раптово, викинувши виняток, нитка звільняє отриманий lock при вході в синхронізований блок. Це одна з причин, чому я віддаю перевагу синхронізованому блоку lock інтерфейсу, який вимагає особливої ​​уваги при звільненні lock'а, зазвичай це досягається звільненням lock'а в блоці finally.
  39. Що таке double checked locking Сінглтон?

  40. Це одне з найпопулярніших питань на інтерв'ю, та все ж, незважаючи на його популярність, шанси, що кандидат відповість на нього, у кращому разі 50%. У половині випадків вони провалюються при написанні коду, а в іншій половині при поясненні, як це було зламано та зафіксовано Java 1.5. Це старий спосіб створення нитки безпечного синглтона, який намагається оптимізувати продуктивність, блокуючись тільки коли екземпляр синглтона створюється вперше, але через складність і факт, що він був зламаний в JDK 1.4, мені особисто він не подобається. Але все-таки, навіть якщо ви не віддаєте перевагу цьому підходу, корисно його знати з погляду інтерв'ю.
  41. Як створити нитку-безпечний Сінглтон?

  42. Це питання доповнює попереднє. Якщо ви скажете, що не любите double checked locking, то інтерв'юер буде змушений запитати про альтернативні способи створення нитки безпечного Сінглтона. І вони є, ви можете скористатися особливостями завантаження класів та ініціалізації статичних змінних для створення екземпляра Сінглтона, або ви можете використовувати переваги потужного типу перерахувань.
  43. Перерахуйте 3 звичаї, яким ви слідуєте у паралельному програмуванні?

  44. Це моє улюблене питання, тому що я вважаю, що потрібно дотримуватися певних правил при написанні паралельного коду, що допомагає у продуктивності, дебазі та підтримці. Далі представлені 3 найкращі правила, яких, я вважаю, повинен дотримуватися кожен Java програміст:
    • Завжди давайте значні імена своїм ниткам
    • Знаходження бага чи відстеження виключення в паралельному коді – досить складне завдання. OrderProcessor, QuoteProcessor або TradeProcessor набагато краще, ніж Thread-1. Thread-2 та Thread-3. Ім'я має відображати завдання, яке виконує ця нитка. Всі великі фреймворки і навіть JDK дотримуються цього правила.
    • Уникайте блокування або зменште масштаб синхронізації
    • Блокування витратне, а перемикання контексту ще витратніше. Намагайтеся уникати синхронізації та блокування наскільки це можливо, і у необхідному мінімумі ви зменшите критичну секцію. Тому я віддаю перевагу синхронізованому блоку синхронізованому методу, тому що це дає вам абсолютний контроль над масштабом блокування.
    • Між синхронізаторами та wait та notify, вибирайте синхронізатори
    • По-перше, синхронізатори типу CountDownLatch, Semaphore, CyclicBarrier або Exchanger спрощують кодинг. Дуже складно реалізовувати складний керуючий потік, використовуючи wait та notify. По-друге, ці класи написані та обслуговуються найкращими у бізнесі і є великий шанс, що вони будуть оптимізовані чи замінені найкращим кодом у наступних релізах JDK. Використовуючи утиліти синхронізації високого рівня, ви автоматично отримуєте всі ці переваги.
    • Між Concurrent Collection та Synchronized Collection, вибирайте Concurrent Collection
    • Це ще одне просте правило, яке легко слідувати і пожинати вигоди. Сучасні колекції більш масштабуються, ніж їх синхронізовані колеги, тому при написанні паралельного коду краще використовувати їх. Так що наступного разу, коли вам знадобиться map, подумайте про ConcurrentHashMap, перш ніж подумаєте про Hashtable.
  45. Як вимушено запустити нитку?

  46. Це питання а як вимушено запустити складання сміття. Коротко, ні, ви, звичайно, можете зробити запит, використовуючи System.gc(), але він нічого не гарантує. У Java немає абсолютно ніякого способу вимушеного запуску нитки, це контролюється планувальником ниток і Java не надає жодного API для його контролю. Це частина Java все ще рандомна.
  47. Що таке фреймворк Fork/Join?

  48. Фреймворк Fork/Join, представлений JDK 7, - це потужна утиліта, що дозволяє розробнику користуватися перевагами декількох процесорів у сучасних серверів. Він розроблений для роботи, яку можна рекурсивно розбити на дрібні частинки. Ціль – використовувати всю доступну обчислювальну потужність, для збільшення продуктивності вашої програми. Одна значна перевага цього фреймворку в тому, що він використовує work-stealing алгоритм (від work – робота і steal – красти). Робочі нитки, у яких закінчабося свої завдання, можуть «поцупити» завдання в інших ниток, які все ще зайняті.
  49. У чому різниця дзвінків методів wait() та sleep()?

  50. Хоча і wait, і sleep уявляють подібність паузи в Java додатку, це пристрої для різних потреб. Wait використовується для внутрішньої комунікації ниток, він поступається lock, якщо умова очікування істинно, і чекає повідомлення, якщо через дії іншої нитки умова очікування хибно. З іншого боку, метод sleep() просто поступається процесором або зупиняє виконання поточної нитки на заданий час. Виклик sleep() не звільняє утримуваний ниткою lock.
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ