Многопоточност в Java
Всяко приложение може да има множество процеси (инстанции). Всеки от тези процеси може да бъде присвоен или като единична нишка, или като множество нишки. В този урок ще видим как да изпълняваме множество задачи едновременно и ще научим повече за нишките и синхронизирането между нишките.
Какво е единична нишка?
Една нишка в Java е основно лека и най-малката единица за обработка. Java използва нишки чрез използване на „Клас нишка“. Има два вида конец – потребителска нишка и демон нишка (daemon threads се използват, когато искаме да почистим приложението и се използват във фонов режим). Когато дадено приложение стартира за първи път, се създава потребителска нишка. Публикувайки това, можем да създадем много потребителски нишки и демон нишки.
Пример за една нишка:
package demotest;
public class GuruThread
{
public static void main(String[] args) {
System.out.println("Single Thread");
}
}
Предимства на единична нишка:
- Намалява режийните разходи в приложението, тъй като се изпълнява една нишка в системата
- Освен това намалява разходите за поддръжка на приложението.
В какво е Multithreading Java?
Многопоточност in Java е процес на изпълнение на две или повече нишки едновременно за максимално използване на процесора. Многонишковите приложения изпълняват две или повече нишки, работещи едновременно. Следователно, той е известен също като паралелност в Java. Всяка нишка върви успоредно една на друга. Множеството нишки не разпределят отделна област на паметта, следователно спестяват памет. Освен това превключването на контекста между нишките отнема по-малко време.
Пример за много нишка:
package demotest;
public class GuruThread1 implements Runnable
{
public static void main(String[] args) {
Thread guruThread1 = new Thread("Guru1");
Thread guruThread2 = new Thread("Guru2");
guruThread1.start();
guruThread2.start();
System.out.println("Thread names are following:");
System.out.println(guruThread1.getName());
System.out.println(guruThread2.getName());
}
@Override
public void run() {
}
}
Предимства на мултинишката:
- Потребителите не са блокирани, тъй като нишките са независими и можем да извършваме множество операции на моменти
- Като такива нишките са независими, другите нишки няма да бъдат засегнати, ако една нишка срещне изключение.
Жизнен цикъл на нишка в Java
Жизненият цикъл на една нишка:

Има различни етапи от жизнения цикъл на нишката, както е показано на горната диаграма:
- НОВ
- Изпълним
- Работещи
- Очакване
- Мъртъв
- Ново: В тази фаза нишката се създава с помощта на клас „Клас на нишка“.Той остава в това състояние до програмата започва нишката. Известен е още като роден конец.
- Работим: В тази страница екземплярът на нишката се извиква с метод за стартиране. Контролът на нишката се дава на планировчика, за да завърши изпълнението. Зависи от планировчика дали да стартира нишката.
- Работещи: Когато нишката започне да се изпълнява, тогава състоянието се променя на състояние „работи“. Планировчикът избира една нишка от пула от нишки и тя започва да се изпълнява в приложението.
- Очакване: Това е състоянието, когато нишката трябва да изчака. Тъй като в приложението се изпълняват множество нишки, има нужда от синхронизация между нишките. Следователно една нишка трябва да изчака, докато другата нишка бъде изпълнена. Следователно това състояние се нарича състояние на изчакване.
- Мъртви: Това е състоянието, когато нишката е прекратена. Нишката е в състояние на изпълнение и веднага щом завърши обработката, тя е в „мъртво състояние“.
Методи на многопоточност в Java
Някои от често използваните методи за нишки са:| Начин на доставка | Descriptйон |
|---|---|
| начало() | Този метод стартира изпълнението на нишката и JVM извиква метода run() на нишката. |
| Сън (int милисекунди) | Този метод кара нишката да заспива, следователно изпълнението на нишката ще спре за предоставени милисекунди и след това нишката отново започва да се изпълнява. Това помага при синхронизирането на нишките. |
| getName () | Връща името на нишката. |
| setPriority(int newpriority) | Променя приоритета на нишката. |
| добив () | Това кара текущата нишка да спре и други нишки да се изпълнят. |
Пример: В тази многопоточна програма в Java Например, ще създадем нишка и ще изследваме вградените методи, налични за нишки.
package demotest;
public class thread_example1 implements Runnable {
@Override
public void run() {
}
public static void main(String[] args) {
Thread guruthread1 = new Thread();
guruthread1.start();
try {
guruthread1.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
guruthread1.setPriority(1);
int gurupriority = guruthread1.getPriority();
System.out.println(gurupriority);
System.out.println("Thread Running");
}
}
Обяснение на кода:
- Code Ред 2: Създаваме клас „thread_Example1“, който имплементира интерфейса Runnable (той трябва да бъде имплементиран от всеки клас, чиито екземпляри са предназначени да бъдат изпълнени от нишката.)
- Code Ред 4: Той отменя метода на изпълнение на интерфейса, който може да се изпълнява, тъй като е задължително да се отменя този метод
- Code Ред 6: Тук сме дефинирали основния метод, в който ще започнем изпълнението на нишката.
- Code Ред 7: Тук създаваме ново име на нишка като „guruthread1“ чрез инстанциране на нов клас нишка.
- Code Ред 8: ще използваме метода „старт“ на нишката, използвайки екземпляр „guruthread1“. Тук нишката ще започне да се изпълнява.
- Code Ред 10: Тук използваме метода „заспиване“ на нишката, използвайки екземпляр „guruthread1“. Следователно нишката ще заспи за 1000 милисекунди.
- Code 9-14: Тук сме поставили метода на заспиване в блока try catch, тъй като има проверено изключение, което възниква, т.е. прекъснато изключение.
- Code Ред 15: Тук задаваме приоритета на нишката на 1, независимо от приоритета, който е бил
- Code Ред 16: Тук получаваме приоритета на нишката с помощта на getPriority()
- Code Ред 17: Тук отпечатваме стойността, извлечена от getPriority
- Code Ред 18: Тук пишем текст, който нишката работи.
Когато изпълните горния код, получавате следния изход:
Изход:
5 е приоритетът на Thread, а Thread Running е текстът, който е изходът на нашия код.
Java Нишка Syncхронизация
При многонишковостта има асинхронно поведение на програмите. Ако една нишка записва някои данни и друга нишка, която чете данни едновременно, може да създаде несъответствие в приложението. Когато има нужда от достъп до споделените ресурси от две или повече нишки, тогава се използва подходът за синхронизация. Java предостави синхронизирани методи за прилагане на синхронизирано поведение.
При този подход, след като нишката достигне вътре в синхронизирания блок, тогава никоя друга нишка не може да извика този метод на същия обект. Всички нишки трябва да изчакат, докато тази нишка завърши синхронизирания блок и излезе от него. По този начин синхронизацията помага в многопоточно приложение. Една нишка трябва да изчака, докато другата нишка завърши своето изпълнение, само тогава другите нишки са разрешени за изпълнение.
Може да се запише в следната форма:
Synchronized(object)
{
//Block of statements to be synchronized
}
Многопоточност в Java Примерни програми
В тази многопоточност Java Например ще вземем две нишки и ще извлечем имената на нишката.
Пример1:
GuruThread1.java
package demotest;
public class GuruThread1 implements Runnable{
/**
* @param args
*/
public static void main(String[] args) {
Thread guruThread1 = new Thread("Guru1");
Thread guruThread2 = new Thread("Guru2");
guruThread1.start();
guruThread2.start();
System.out.println("Thread names are following:");
System.out.println(guruThread1.getName());
System.out.println(guruThread2.getName());
}
@Override
public void run() {
}
}
Обяснение на кода:
- Code Ред 3: Взехме курс „Guru„Thread1“, който имплементира Runnable (трябва да бъде имплементиран от всеки клас, чиито инстанции са предназначени да бъдат изпълнявани от нишката.)
- Code Ред 8: Това е основният метод на класа
- Code Ред 9: Тук създаваме класа Thread и създаваме екземпляр с име „guruThread1“ и създаваме нишка.
- Code Ред 10: Тук създаваме клас Thread и създаваме екземпляр с име „guruThread2“ и създаваме нишка.
- Code Ред 11: Започваме нишката, т.е. guruThread1.
- Code Ред 12: Започваме нишката, т.е. guruThread2.
- Code Ред 13: Извеждане на текста като „Имената на нишките са следните:“
- Code Ред 14: Получаване на името на нишка 1 с помощта на метода getName() на класа на нишката.
- Code Ред 15: Получаване на името на нишка 2 с помощта на метода getName() на класа на нишката.
Когато изпълните горния код, получавате следния изход:
Изход:
Имената на нишките се извеждат тук като
- Guru1
- Guru2
Пример 2:
В тази многопоточност в Java Например, ще научим за заместването на методите run() и start() метода на изпълняващ се интерфейс и ще създадем две нишки от този клас и ще ги стартираме съответно.
Освен това взимаме два класа,
- Такъв, който ще реализира работещия интерфейс и
- Друг, който ще има основния метод и ще се изпълнява съответно.
package demotest;
public class GuruThread2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
GuruThread3 threadguru1 = new GuruThread3("guru1");
threadguru1.start();
GuruThread3 threadguru2 = new GuruThread3("guru2");
threadguru2.start();
}
}
class GuruThread3 implements Runnable {
Thread guruthread;
private String guruname;
GuruThread3(String name) {
guruname = name;
}
@Override
public void run() {
System.out.println("Thread running" + guruname);
for (int i = 0; i < 4; i++) {
System.out.println(i);
System.out.println(guruname);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("Thread has been interrupted");
}
}
}
public void start() {
System.out.println("Thread started");
if (guruthread == null) {
guruthread = new Thread(this, guruname);
guruthread.start();
}
}
}
Обяснение на кода:
- Code Ред 2: Ето ни тук, посещаваме един клас.Guru„Тема2“, която ще съдържа основния метод.
- Code Ред 4: Тук вземаме основен метод на класа.
- Code Ред 6-7: Тук създаваме екземпляр на клас GuruThread3 (която е създадена в долните редове на кода) като „threadguru1“ и стартираме нишката.
- Code Ред 8-9: Тук създаваме друг екземпляр на класа GuruThread3 (която е създадена в долните редове на кода) като „threadguru2“ и стартираме нишката.
- Code Ред 11: Тук създаваме клас „Guru„Thread3“, който имплементира изпълнимия интерфейс (той трябва да бъде имплементиран от всеки клас, чиито екземпляри са предназначени да бъдат изпълнявани от нишката.)
- Code Ред 13-14: ние вземаме две променливи на класа, от които едната е от класа тип нишка, а другата от класа низ.
- Code Ред 15-18: ние отменяваме GuruКонструкторът Thread3, който приема един аргумент от тип низ (който е името на нишката), който се присвоява на променливата на класа guruname и следователно името на нишката се съхранява.
- Code Ред 20: Тук заместваме метода run() на интерфейса, който може да се изпълнява.
- Code Ред 21: Ние извеждаме името на нишката с помощта на оператор println.
- Code Ред 22-31: Тук използваме for цикъл с брояч, инициализиран на 0, и той не трябва да бъде по-малък от 4 (можем да вземем произволно число, следователно тук цикълът ще се изпълнява 4 пъти) и увеличаваме брояча. Ние отпечатваме името на нишката и също така правим нишката да заспи за 1000 милисекунди в рамките на блок try-catch, тъй като методът на заспиване повдигна проверено изключение.
- Code Ред 33: Тук заместваме метода за стартиране на интерфейса, който може да се изпълнява.
- Code Ред 35: Извеждаме текста „Нишката е започната“.
- Code Ред 36-40: Тук вземаме условие if, за да проверим дали променливата на класа guruthread има стойност в нея или не. Ако е null, тогава създаваме екземпляр, използвайки клас нишка, който приема името като параметър (стойността, за която е зададена в конструктора). След което нишката се стартира с помощта на метода start().
Когато изпълните горния код, получавате следния изход:
Продукция:
Следователно има две нишки, получаваме два пъти съобщение „Нишката е стартирана“.
Получаваме имената на нишката, както сме ги извели.
Влиза в for цикъл, където отпечатваме брояча и името на нишката и броячът започва с 0.
Цикълът се изпълнява три пъти и между тях нишката е заспала за 1000 милисекунди.
Следователно, първо получаваме guru1, след това guru2 и отново guru2, защото нишката спи тук за 1000 милисекунди и след това следва guru1 и отново guru1, нишката спи за 1000 милисекунди, така че получаваме guru2 и след това guru1.
Oбобщение
В този урок видяхме многонишкови приложения Java и как да използвате единична и многонишкова нишка в Java.
- Обяснете многопоточността в Java: при многопоточност потребителите не се блокират, тъй като нишките са независими и могат да извършват множество операции наведнъж
- Различни етапи от жизнения цикъл на нишката са,
- НОВ
- Изпълним
- Работещи
- Очакване
- Мъртъв
- Научихме и за синхронизация между нишки, което помага на приложението да работи гладко.
- Многопоточно програмиране в Java улеснява много повече задачи на приложението.



