Нить - перші кроки
Коли на співбесіді порушується питання мнопоточності, то я себе відчуваю вкрай незатишно. І не тому, що погано знаю цей предмет - гадаю, що я його розумію досить непогано. Але священний трепет і таємниця, якими оповита ця область знань, мене дратують. Тому як хоч це і складно, але цілком зрозумілі. А ось собеседователі можуть шукати (і знаходити) зовсім інші смисли і особливості. Можна не зійтися в думках :).
Якщо зрозуміти, що саме там викликає складність і які саме інструменти вам пропонуються, то далі проблема вже не в самій многопоточности, але в складності управління завданнями, для яких вона використовується. Розіб'ємо нашу розповідь на кілька частин:
- Навіщо потрібна багатопоточність?
- Як створювати потоки
- Які проблеми виникають і чому
- Інструменти для вирішення проблем
Цілком допускаю, що моє сприйняття суб'єктивно і якісь моменти і тонкощі можуть не потрапити в цей опис. Просто тому, що чим глибше занурюватися в цю проблематику, тим більша кількість цікавих моментів можна виявити (на рівні реалізації JVM або на рівні архітектури процесорів). Також необхідно врахувати, що характер вирішуваних завдань теж впливає - адже саме при вирішенні задач ми натрапляємо на будь-які обмеження, особливості реалізації та інші хитрі моменти.
Навіщо потрібна багатопоточність
Відповідь на це питання не є проблемою. На сьогодні кількість процесорів в серверних системах більше одного, та й один процесор має кілька ядер. Предагаем продемонструвати це на прикладі. Будьте уважні - клас знаходиться в пакеті edu.javacourse.threads
Ще не вдавайтеся в подробиці - просто запустіть цей чудовий приклад, але перед цим раджу запустити диспетчер задач, щоб подивитися завантаження процесорів. Ось яка картинка спостерігається у мене.
Потоки дозволяють в ручному режимі запускати кілька завдань в рамках однієї програми. У найпростішому варіанті всередині однієї програми завжди є один основний потік. Завжди. А ось додаткові потоки ми повинні запускати самі. І запуск - не найскладніше. Саме сложнгое змусити їх працювати спільно. Але про це ми поговоримо пізніше. А поки давайте просто навчимося запускати потоки.
Як створювати потоки
Для запуску потоків (можете посміхнутися) існує спеціальний клас - Thread (потік). Також є ще два інтерфейси, але як з ними працювати, ми розберемо трохи пізніше. Напишемо найпростіше додаток і розберемо його в подробицях.
Спочатку пропоную подивитися на код класу SimpleRunnable. Як бачимо він не сильно відрізняється від попереднього випадку - відмінність полягає в тому, що ми не успадковуємо від класу Thread. а реалізуємо інтерфейс Runnable. Переопредеяемий метод точно такий же, як і був раніше - run. відмінності мінімальні.
Тепер звернемо увагу на клас SimpleThreadManager. Як бачимо тут ми використовуємо дещо інший алгоритм запуску потоку. Спочатку створюємо об'єкт класу SimpleRunnable. потім створюємо об'єкт класу Thread. якому в конструкторі передаємо наш об'єкт. І вже після цього викликаємо метод start. У момент виклику start классThread перевіряє, чи не передавали йому в конструкторі об'єкт, який реалізує інтерфейс Runnable. Якщо так - то запускається метод run переданого об'єкта. Якщо немає - об'єкт Thread буде виконувати свій метод run. Загалом теж досить нескладно.
Ви можете задуматися - а навіщо створили інтерфейс, коли є клас Thread. Відповідь в общем-то очевидний - в надзвичайній гнучкості. Адже в цьому випадку запускатися в окремому потоці може навіть дуже клас. Тобто ми можемо створити клас для складного розрахунку - наприклад, для обчислення прибутковості робіт /
закупівель / і т.д. за договором. Це і ходіння в базу даних, і якісь файли, можливо зовнішні запити в інші системи. Загалом - довго. І таких договорів штук 40. Тепер ми можемо запускати розрахунок декількох договорів паралельно і при цьому цей складний клас зовсім не повинен бути спадкоємцем Thread.
передача параметрів
В якості домашнього завдання спробуйте написати форму, яка «бігає» по екрану зліва направо (або зверху вниз) і при досягненні межі починає рухатися в інший бік.
Тепер ми можемо перейти до наступної частини розповіді про багатопоточності, яка введе вас в світ жахливих жахів, що виникають при спільній роботі декількох потоків :).
Дякуємо. Я доповнив статтю - тепер вона містить те, що я хотів. Але многопоточность на цій статті не закінчиться - там ще багато цікавого.
Таким чином, процесор сам вибирає як распараллеливать процеси в багатопотокової середовищі?
Там все дуже складно і я сам не все точно можу розповісти 🙂 По суті потоки - це об'єкти операційної системи (Windows, Linux). JVM створює потоки, як об'єкти операційної системи і ними в якійсь мірі керує. Але сама ОС це теж робить і саме вона «завантажує» процесор завданнями і потоками.
Якщо чесно - я не настільки глибоко занурювався в JVM, щоб відповісти більш докладно. Цілком допускаю, що навіть в цих рядках я щось наплутав.
Привіт, а можете, будь ласка, пояснити саме 1-е додаток де ви порівнюєте роботу обчислень в 1 потік і в многопоточности. Особливо клас BigTaskManyThreads.
Робота з потоками в кінцевому підсумку контролюється операційною системою і Linux це робить інакше, ніж Windows. Так що такі варіанти можливі - Linux намагається не давати одному процесу завантажити всі CPU дуже сильно.
»Зробив це у вигляді параметра для конструктора, але точно також можна зробити це через виклики сеттерів (пропоную вам самим реалізувати такий варіант - це нескладно).»
Нескладно, але для новачка робити обов'язково без підказок, відмінне завдання для поглиблення розуміння і закріплення раніше пройденого матеріалу.
ВАЖЛИВО. При роботі з локалізацією є один момент - якщо ви збираєтеся використовувати російські букви, то ви не зможете писати з напряму.
По-перше той же NetBeans відстежує таку ситуацію автоматично. IDEA теж - правда їй треба про це сказати в налаштуваннях.