ся.
} catch (InterruptedException e) {}. out.println ( Першим з'явилося яйце! );
}//якщо опонент вже закінчив висловлюватися
{. out.println ( Першою з'явилася курка! );
}. out.println ( Суперечка закінчено! );
}
}
Консоль:
Суперечка розпочато ...
курка!
яйце!
яйце!
курка!
яйце!
курка!
яйце!
курка!
яйце!
курка!
Першою з'явилася курка!
Суперечка закінчено!
У наведеному прикладі два потоки паралельно протягом 5 секунд виводять інформацію на консоль. Точно передбачити, який потік закінчить висловлюватися останнім, неможливо. Можна спробувати, і можна навіть вгадати, але є велика ймовірність того, що та ж програма при наступному запуску матиме іншого «переможця». Це відбувається через так званого «асинхронного виконання коду». Асинхронність означає те, що не можна стверджувати, що яка-небудь інструкція одного потоку, виконається раніше чи пізніше інструкції іншого. Або, іншими словами, паралельні потоки незалежні один від одного, за винятком тих випадків, коли програміст сам описує залежності між потоками за допомогою передбачених для цього коштів мови.
1.4 Завершення процесу і демони
У Java процес завершується тоді, коли завершується останній його потік. Навіть якщо метод main () вже завершився, але ще виконуються породжені ним потоки, система буде чекати їх завершення. Однак це правило не відноситься до особливого виду потоків - демонам. Якщо завершився останній звичайний потік процесу, і залишилися тільки потоки-демони, то вони будуть примусово завершені і виконання процесу закінчиться. Найчастіше потоки-демони використовуються для виконання фонових завдань, обслуговуючих процес протягом його життя.
Оголосити потік демоном досить просто - потрібно перед запуском потоку викликати його метод setDaemon (true);
Перевірити, чи є потік демоном, можна викликавши його метод boolean isDaemon ();
1.5 Завершення потоків
У Java існують (існували) кошти для примусового завершення потоку. Зокрема метод Thread.stop () завершує потік негайно після свого виконання. Однак цей метод, а також Thread.suspend (), що припиняє потік, і Thread.resume (), що продовжує виконання потоку, були оголошені застарілими і їх використання відтепер вкрай небажано. Справа в тому що потік може бути «убитий» під час виконання операції, обрив якої на півслові залишить деякий об'єкт в неправильному стані, що призведе до появи важко відловлюють і випадковим чином виникає помилку.
Замість примусового завершення потоку застосовується схема, в якій кожен потік сам відповідальний за своє завершення.
Потік може зупинитися або тоді, коли він закінчить виконувати методу run (), (main () - для головного потоку) або по сигналу з іншого потоку. Причому як реагувати на такий сигнал - справа, знову ж, самого потоку. Отримавши його, потік може виконати деякі операції і завершити виконання, а може і зовсім його проігнорувати і продовжити виконуватися. Опис реакції на сигнал завершення потоку лежить на плечах программіста.імеет вбудований механізм оповіщення потоку, який називається Interruption (переривання, втручання), і скоро ми його розглянемо, але спочатку подивіться на наступну програмку:
Приклад 5.- потік, який щосекунди додає чи віднімає одиницю із значення статичної змінної Program.mValue. Incremenator містить два закритих поля - mIsIncrement і mFinish. Те, яку дію виконується, визначається булевої змінної mIsIncrement - якщо воно дорівнює true, то виконується додаток одиниці, інакше - віднімання. А завершення потоку відбувається, коли значення mFinish стає одно true.
class Incremenator extends Thread
{
//Про ключовому слові volatile - трохи ніжеvolatile boolean mIsIncrement=true; volatile boolean mFinish=false;
public void changeAction ()//Міняє дію на протилежне
{=! mIsIncrement;
} void finish ()//Ініціює завершення потоку
{= true;
}
Overridevoid run ()
{
{(! mFinish)//Перевірка на необхідність завершення
{(mIsIncrement) .mValue ++;//Інкремент
Program.mValue -;//Декремент
//Висновок поточного значення змінної
System.out.print (Program.mValue + );
};//Завершення потоку
{. sleep (1000);//Призупинення потоку на 1 сек.
} catch (InterruptedException e) {}
} (true);
}
}
class Program
{
//змінна, яка оперує інкременатор
public static int mValue=0;
Incremenator mInc;//Об'єкт побаченого потоку
static void main (String [] args)
{= new Incremenator ();//Створення потоку
.out.print ( Значення=);
mIn...