
- •1. Історія створення Java.
- •2. Історія розвитку Java
- •3.Опишіть поняття “об’єкт”
- •4. Опишіть поняття “клас”
- •5. Опишіть типи відношень між класами
- •6. Переваги і недоліки об’єкто-зорієнтованого програмування
- •7. Опишіть правила побудови ідентифікаторів мови Java, наведіть приклади
- •8. Поняття літералів. Приклади
- •9. Оператори та операції в мові Java
- •11. Типи даних у мові Java
- •12. Клас Object
- •13. Клас String
- •14. Клас Class
- •15. Імена в Java
- •16. Пакети в Java
- •17. Область видимості імен
- •18.Об’ява класів у Java
- •19.Приведення типів у Java
- •21.Приведення посилальних типів даних.
- •22.Приведення до рядка.
- •23.Заборонені приведення.
- •24.Застосування приведення типів.
- •25.Статичні елементи.
- •26. Ключові слова this і super.
- •27. Ключове слово abstract.
- •28. Поняття інтерфейсів.
- •29. Поліморфізм.
- •30. Масиви в Java.
- •31. Приведення типів для масивів.
- •32. Клонування масивів.
- •33. Керування ходом виконання програми.
- •34. Нормальне і перерване виконання операторів.
- •35. Блоки і локальні змінні.
- •36. Порожній оператор.
- •38. Синтаксис оператора if.
- •39. Синтаксис оператора switch.
- •40. Керування циклами.
- •41.Синтаксис оператора while
- •42.Ситаксис оператора do
- •43.Синтаксис оператора for
- •44.Оператори break I continue
- •45.Іменовані блоки
- •46. Оператор return
- •47. Оператор synchronized
- •48. Помилки при роботі програми. Виняткові ситуації
- •48. Помилки при роботі програми. Виняткові ситуації
- •49.Причини виникнення помилок
- •50.Обробки виняткових ситуацій
- •51.Конструкція try-catch-finally
- •52.Використання оператора throw
- •53.Виняткові ситуації, які перевіряються і які не перевіряються
- •54.Створення класів користувача обробки виняткових ситуацій
- •55.Поняття потокв в Java
- •56.Базові класи для роботи з потоками
- •57.Класс Thread
- •58. Інтерфейс Runnable
- •60. Потоки-демони
- •61.Синхронізація роботи потоків.
- •62.Класи обгортки для примітивних типів.
- •63.Клас Math.
- •66.Клас Calendar.
- •67.Клас TimeZone.
- •68. Колекції java
- •69.Інтерфейс Collection.
- •70.Інтерфейс Set.
- •71.Інтерфейс List.
- •72.Інтерфейс Map.
- •73.Інтерфейс SortedSet.
- •74.Інтерфейс SortedMap.
- •75.Інтерфейс Iterator.
- •76.Конкретні класи колекцій.
- •77.Клас Properties.
- •78. Інтерфейс Comparator.
- •79.Клас BitSet.
- •80.Клас Random.
- •81.Система введення/виведення. Потоки даних.
- •82.Класи реалізації потоків даних.
- •84. Робота із файловою системою.
- •59. Робота із пріоритетами потоків
61.Синхронізація роботи потоків.
При багатопотоковій архітектурі додатка можливі ситуації, коли декілька потоків будуть одночасно працювати з одними і тими ж даними, використовуючи їх значення та привласнюючи нові. У такому випадку результат роботи програми стає неможливим зумовити, дивлячись тільки на вихідний код. Фінальні значення змінних будуть залежати від випадкових чинників, виходячи з того, який потік яку дію встиг зробити першим або останнім.
4.1 . Зберігання змінних в пам'яті
Віртуальна машина підтримує основне сховище даних (основний зберігання) , в якому зберігаються значення всіх змінних і яке використовується всіма потоками . під змінними тут розуміються поля об'єктів і класів , а також елементи масивів . Що стосується локальних змінних і параметрів методів , їх значення не можуть бути доступним іншим потокам , тому вони не представляють інтересу . Для кожного потоку створюється його власна робоча пам'ять ( оперативна пам'ять) , в яку копіюються значення всіх змінних перед використанням. Розглянемо основні операції, доступні для потоків при роботі з пам'яттю : • use - читання значення змінної з робочої пам'яті потоку • assign - запис значення змінної в робочу пам'ять потоку • read - отримання значення змінної з основного сховища • load - збереження значення змінної , прочитаного з основного сховища , в робочій пам'яті • store - передача значення змінної з робочої пам'яті в основне сховище для майбутнього збереження • write - зберігає в основному сховище значення змінної , переданої командою store Підкреслимо , що перераховані команди не є методами будь-яких класів , вони не доступні програмісту . Сама віртуальна машина використовує їх для забезпечення коректної роботи потоків виконання. Потік , працюючи з змінної , регулярно застосовує команди використання призначити і для використання її існуючого значення і присвоєння нового. Крім цього , повинні здійснюватися дії по передачі значень із / в основне сховище . Вони виконуються в два етапи.
При отриманні даних спочатку основне сховище зчитує значення командою читання , а потім потік зберігає результат у своїй робочої пам'яті командою навантаження. Ця пара команд завжди виконується разом саме в такому порядку , тобто не можна виконати одну , чи не виконавши іншу. При відправленні даних спочатку потік зчитує значення з робочої пам'яті командою магазин , а потім основне сховище зберігає його командою запису. Ця пара команд також завжди виконується разом саме в такому порядку , тобто не можна виконати одну , не виконавши іншу. Набір цих правил складався з тим , щоб операції з пам'яттю були досить суворі для точного аналізу їх результатів , а з іншого боку правила повинні залишати
достатній простір для різних технологій оптимізацій (регістри , черги ,
кеш і т.д.). Послідовність команд підпорядковується таким правилам :
• всі дії, що виконуються одним потоком строго впорядковані , тобто виконуються одно
за іншим
• всі дії , що виконуються з однієї змінної в основному сховище пам'яті , строго
впорядковані , тобто слідують одне за іншим
За винятком деяких додаткових очевидних правил більше ніяких обмежень немає. Наприклад , якщо потік змінив значення спочатку однією , а потім іншої змінної , то вони ці зміни можуть бути передані в основне сховище в переставлених порядку.
Потік створюється з чистою робочою пам'яттю і повинен завантажити всі необхідні змінні з основного сховища перед використанням. Будь-яка змінна спочатку створюється в основному сховищі і лише потім копіюється в робочу пам'ять потоків , які будуть її використовувати. Таким чином , потоки ніколи не взаємодіють один з одним на пряму , тільки через головне сховище .
4.2 . модифікатор volatile
При оголошенні полів об'єктів і класів може бути вказаний модифікатор volatile . Він встановлює більш суворі правила роботи зі значеннями змінних. Якщо потік збирається виконати команду use для volatile змінної , то потрібно, щоб попереднім дією над цієї змінної було обов'язково load , і на оборот - операція load може виконуватися тільки перед use . Таким чином , змінна і головне сховище завжди мають саме останнє значення цієї змінної . Аналогічно , якщо потік збирається виконати команду store для volatile змінної , то потрібно, щоб попереднім дією над цієї змінної було обов'язково assign , і навпаки - операція assign може виконуватися тільки якщо наступною буде store . Таким чином , змінна і головне сховище завжди мають саме останнє значення цієї змінної . Нарешті , якщо проводяться операції над декількома volatile змінними , то передача відповідних змін до основного сховища повинно проводиться строго в тому ж порядку. При роботі із звичайними змінними компілятор має більше простору для маневру. Наприклад , за сприятливих обставин може виявитися можливим передбачити значення змінної , заздалегідь обчислити і зберегти його , а потім у потрібний момент використовувати вже готовим. Потрібно звернути увагу на два 64 - розрядних типу double і long . Оскільки багато платформи підтримують лише 32 -бітну пам'ять , величини цих типів розглядаються як дві змінні , і всі описані дії робляться незалежно для двох половинок таких значень . Звичайно , якщо виробник віртуальної машини вважає за можливе , він може забезпечити атомарность операцій і над цими типами . Для volatile змінних це є обов'язковою вимогою .
4.3 . блокування
В основному сховище для кожного об'єкта підтримується блокування ( lock ) , над якою можна провести дві дії - встановити ( lock ) і зняти ( unlock ) . Тільки один потік в один момент часу може встановити блокування на деякий об'єкт . Якщо до того , як цей потік виконає операцію unlock , інший потік спробує встановити блокування , його виконання буде призупинено доти , поки перший потік не відпустить її . Операції lock і unlock накладають жорстке обмеження на роботу з змінними в робочій пам'яті потоку . Після успішно виконаного lock , робоча пам'ять очищається , і всі змінні необхідно заново зчитувати з основного сховища. Аналогічно , перед операцією unlock необхідно всі змінні зберегти в основному сховищі. Важливо підкреслити , що блокування є чимось на зразок прапора. Якщо блокування на об'єкт встановлена , це не означає , що цим об'єктом не можна користуватися , що його
поля і методи стають недоступними - це не так. Єдина дія , яке стає неможливим - встановити цю ж блокування іншому потоку до тих пір, поки перший потік не виконає unlock . У Java -програмі для того , щоб скористатися механізмом блокувань , існує ключове слово synchronized . Воно може бути застосоване у двох варіантах - для оголошення synchronized - блоку і як модифікатор методу . В обох випадках дія його
приблизно однакове.
Synchronized - блок записується таким чином :
synchronized ( ref ) {
...
}