Раптове закриття java-додатки як уникнути

Java: Статті Раптове закриття Java-програми: як уникнути?

У багатьох випадках, ви сподіваєтеся на те, що користувач закриє додаток "нормальним" для вас способом. Наприклад, в першому випадку ви можете надати йому компонент JButton, після кліка на який виконуються необхідні завершальні операції і здійснюється безпосередньо вихід з програми. Як альтернативний варіант ви можете повісити обробник події вікна, який би обробляв подія windowClosing. Tomcat ж використовує спеціальний batch-файл, який може бути виконаний при правильному завершенні роботи з додатком. Однак, добре відомо, що користувачі далеко не так часто коректно завершують роботу з додатками. Вони можуть робити з додатками все, що побажають. Крім цього користувач може просто-напросто закрити консоль або завершити свій сеанс роботи з операційною системою, залишивши при цьому ваш додаток незакритим.

В Java, "віртуальна" машина завершує роботу в двох випадках: по-перше, коли з програми вийшли нормальним способом, тобто був викликаний метод System.exit або ж коли залишився останній потік не є демоном. По-друге, коли користувач раптово перериває роботу "віртуальної" машини, наприклад, натискаючи комбінацію клавіш Ctrl + C або ж виходячи з системи, не замкнувши попередньо працює Java-додаток.

На щастя, віртуальна машина слід наступної двухфазной послідовності дій, перш ніж вивантажити себе:

  1. Віртуальна машина запускає всі зареєстровані shutdown-пастки, якщо такі були встановлені. Shutdown-пастки - це нитки (threads), які реєструються за допомогою класу Runtime. Всі ці пастки будуть запущені і будуть працювати паралельно до тих пір, поки всі вони не завершать своєї роботи.
  2. Віртуальна машина викликає все певні finalize-операції (якщо є відповідні).

У цій статті ми розглянемо перший пункт, оскільки він дозволяє програмісту спантеличити "віртуальну" Java-машину виконанням необхідних операцій по завершенню програми. Shutdown-пастки - це просто екземпляри класів-спадкоємців класу Thread. Щоб створити таку пастку потрібно виконати наступну послідовність дій:

  1. Описати клас, що успадковує клас Thread.
  2. Здійснити реалізацію методу run цього нового класу. Цей метод містить код, який і буде виконуватися по завершенню роботи "віртуальної" машини незалежно від того, нормально чи ні було завершено додаток.
  3. Зв'язати клас shutdown-пастки з вашим додатком.
  4. Зареєструвати пастку за допомогою методу addShutdownHook поточного екземпляра класу Runtime.

Як ви вже могли помітити, вам не потрібно запускати тільки що створену нитка пастки, як ви б запускали інший клас, який успадкував Thread. Турбота про запуск цієї нитки лягає на "віртуальну" машину, яка, підійшовши до виконання своєї shutdown-послідовності, запустить всі зареєстровані нитки пасток.

Код лістингу 1 представляє простий клас ShutdownHookDemo і підклас класу Thread - ShutdownHook. Врахуйте, що метод run класу ShutdownHook просто виводить рядок "Shutting down" на консоль. Звичайно, ви можете вставити абсолютно будь-який код, який вам необхідно виконати під час завершення вашої програми.

Після запуску public-класу, викликається метод start. Метод start створює shutdown-пастку і реєструє її в поточному екземплярі Runtime-клас

Після цього програма чекає натискання користувачем клавіші Enter.

Коли користувач натискає Enter, здійснюється вихід їх програми. Однак перед виходом "віртуальна" машина запускає зареєстровану shutdown-пастку, яка в свою чергу друкує рядок "Shutting down".

В якості наступного прикладу ми розглянемо просте Swing-додаток, головний клас якого називається MySwingApp. Ця програма створює тимчасовий файл при запуску. Коли воно закривається, файл повинен бути знищений. Код цієї програми наведений в лістингу 2.

Раптове закриття java-додатки як уникнути

Listing 2.

При запуску, це додаток викликає метод initialize. Цей метод, в свою чергу, створює в поточному каталозі тимчасовий файл з ім'ям temp.txt.

Коли користувач закриває цей додаток, то тимчасовий файл повинен бути знищений. В даному випадку нам залишається сподіватися на те, що користувач натисне кнопку Exit, і, по її натисканні, буде викликаний метод shutdown, який і видаляє тимчасовий файл. Однак тимчасовий файл не буде видалений в разі, якщо користувач для виходу з програми скористається системної кнопкою X вікна програми або будь-яким іншим способом.

У лістингу 3 наведено варіант цього ж додатка, який вирішує цю проблему. Новий варіант програми модифікує код з лістингу 2, встановлюючи shutdown-пастку. Клас цієї пастки визначається як внутрішній клас основного класу програми. Таким чином, він отримує доступ до всіх полів і методів основного класу. У лістингу 3, метод run класу-пастки просто викликає метод shutdown основного класу. Цим гарантується його виклик по завершенню програми.

Лістинг 3.

Зверніть увагу на метод initialize. Перше, що він робить - створює екземпляр внутрішнього класу MyShutdownHook, який успадковує клас Thread.

Тепер, отримавши примірник класу MyShutdownHook, ми реєструємо його в Runtime за допомогою методу addShutdownHook:

Частина, що залишилася методу initialize в точності відповідає таким же методом з лістингу 2. У цій частині створюється тимчасовий файл і виводиться рядок "Creating temporary file".

Тепер спробуйте запустити це невелике Swing-додаток. Переконайтеся в тому, що тимчасовий файл видаляється в будь-якому випадку, яким би способом ви не закрили додаток.

Shutdown-пастки, які ми розглянули в цій статті, є фактично єдиним правильним рішенням проблеми виконання будь-якого коду по завершенню програми. А оскільки не можна бути впевненим в тому, яким чином користувач на цей раз закриє ваш додаток - їх використання значно полегшить вам життя, гарантуючи виконання встановлених вами правил завершення програми.


Warning. mysql_connect () [function.mysql-connect]: Can not connect to local MySQL server through socket '/tmp/mysql.sock' (2) in /pub/home/javaport/javaportal/books/show2b.php on line 11

Warning. mysql_db_query () [function.mysql-db-query]: Can not connect to local MySQL server through socket '/tmp/mysql.sock' (2) in /pub/home/javaport/javaportal/books/show2b.php on line 19

Warning. mysql_db_query () [function.mysql-db-query]: A link to the server could not be established in /pub/home/javaport/javaportal/books/show2b.php on line 19

Warning. mysql_fetch_array (): supplied argument is not a valid MySQL result resource in /pub/home/javaport/javaportal/books/show2b.php on line 30
Дізнайся про що ти насправді зараз думаєш тут.


[An error occurred while processing this directive]


Warning. mysql_connect () [function.mysql-connect]: Can not connect to local MySQL server through socket '/tmp/mysql.sock' (2) in /pub/home/javaport/javaportal/news/worldnews.php on line 91

Warning. mysql_db_query () [function.mysql-db-query]: Can not connect to local MySQL server through socket '/tmp/mysql.sock' (2) in /pub/home/javaport/javaportal/news/worldnews.php on line 93

Warning. mysql_db_query () [function.mysql-db-query]: A link to the server could not be established in /pub/home/javaport/javaportal/news/worldnews.php on line 93

Warning. mysql_fetch_array (): supplied argument is not a valid MySQL result resource in /pub/home/javaport/javaportal/news/worldnews.php on line 95