ПредишенСледващото

В тази статия, аз ще се занимае с голям и сложен въпрос на мултитрединга в Java. Разбира се, всичко в една статия не мога да кажа, затова ще споменем само най-основните теми.


Предимствата на многонишкова
Въпреки многото предизвикателства, многонишково е много полезен в потребителски интерфейси. Докато една нишка се занимава с обработка на данни, вторият спокойно черпи графика. В резултат на това, което виждаме на екрана, гладка анимация и може да взаимодейства с елементи от интерфейса, без страх, че всичко замръзва.

Multithreading също така подобрява скоростта на обработка: докато един подготвя потока от данни, например, изпомпване от интернет на малки порции, втора и трета потоци могат да ги обработват и регистрират в резултат на четвърти диск.

Ако имаме многоядрен процесор, потоците значително ще подобрят ефективността на работа, чрез пренасочване към други ядро.


Е, достатъчно теория, нека минем към практиката.


Създаване потоци
В Java за стрийминг е класа Thread. Има два начина за създаване на нова тема, но те могат да бъдат написани, когато голям брой начини.

Първият вариант е разширение на класа Thread.

обществени клас CustomThread разширява темата # 123;

System. навън. println # 40; 6 # 41; ;


Можете дори да си поиграете с API за размисъл, но това е наистина харесвам себе си нещо.


Прекъсването на конци
Да, това се прекъсва и не спре или пауза. Потоци не могат да бъдат спрени по стандартен начин, защото това е свързано с много проблеми. Следователно, методът на стоп, да спре, пауза, и да унищожи в класа по темата са отбелязани като оттеглен. Така че спрете да трябва да направя всичко сам.

Като цяло, в нишка Java работи толкова дълго, тъй като кодът се изпълнява в метод на пътуванията. Ако изпълнението е проста операция, например, текст изхода на конзолата, потокът веднага след завършване на операцията. Ако сме в данните за запис на потока в един цикъл от 100 файла, потокът ще работи толкова дълго, колкото са свършили задачата си.

И, между другото, ако конецът работи във фонов режим и да затворите програмата, процесът на програмата ще бъде все още виси във фонов режим, докато не приключи всичко на нишките. Това в края на програмата е гарантирано да получите завършването на потока, е необходимо да се направи на потока на демона. Това звучи смешно, но това е така:

нишка. setDaemon # 40; вярно # 41;


Така че, ние имаме една нишка, която изпълнява в цикъл някои повтарящи работа, и ние трябва да се известно време, за да го изпълни. Най-очевидният начин е да има булева променлива и да следи за неговото състояние. Най-често го направите:

частен Булева isRunning;

Всички теми завършени. Counter = 5000

Как ще функционира:
- Ние сме създали два потока и да ги изпълнява.
- Да приемем, първи поток е започнал по-бързо и влезе в Докато цикъл. Докато втората пистите.
- Първите поток блок петна синхронизирани. Проверки - дали има в момента е в този блок други теми? Не, така че първата нишка влиза в устройството. Второ, все още влиза в цикъл време.
- Първият поток сега е в линия за брояч се увеличава. Вторият поток достигне синхронизирано блок. Отново, проверка и като поток вътре е, не е получил разрешение да влезем вътре, и по тази причина втората нишка чака.
- Първият поток е все още в течение на. Вторият поток е все още само чакат.
- Накрая първия поток напуска за линия и напуска зоната на синхронизация. Вторият поток получава разрешение да влезе вътре.

По този начин, синхронизирано операция потоци.


Синхронизиране на блока трябва да се поставят разумно. Ако сме направили нещо като това:

частен статично невалидни printCounter # 40; # 41; # 123;

синхронизирано # 40; Counter. клас # 41; # 123;

докато # 40; Counter. получавам # 40; # 41; <5000 ) {

за # 40; INT I = 0; аз <10 ; i ++ ) {

Counter. увеличение # 40; # 41; ;

Тема. сън # 40; 1 # 41; ;

# 125; улов # 40; InterruptedException ех # 41; # 123;

Тема. currentThread # 40; # 41. прекъсвам # 40; # 41; ;


щяхме да получи правилния резултат от 5000, само за да са работили само една нишка:
- Създаване на две теми и да ги изпълнява.
- Да приемем, първи поток е започнал по-бързо и отиде в единица време. Докато втората пистите.
- Първият поток е сега, докато линия. Вторият поток е изпълнено synchonized блок и не се получи разрешение за влизане.
- Първият поток работи. Второ чакащите.
- След известно количество време, първо разходомера се увеличи до 5000 цикъла и лявата и синхронизация блок. Вторият поток е позволено да влезе вътре.
- Първият поток е завършен. Вторият поток се провери това условие Counter.get () <5000 уже не выполняется и не вошёл в цикл while. Покинул блок синхронизации и завершился.


Друго решение на проблема с електромера - което го прави най получи и увеличение синхронизирани. След това не се изисква синхронизиране блок в метода на бягане.

обществени клас SynchronizedCounter # 123;

частен статичен Int брояч = 0;


Тоест, ние отидем в блока за синхронизация, монитор. Върнатата стойност и да излезете от монитора. Ако по време на критичния участък беше изключение, ние също излиза от монитора.

В синхронизиран метод инструкции байткод и monitorenter monitorexit, че не е, но това не означава, че няма влизане в монитора. Синхронизирано флаг на метода на JVM казва, че всички тези инструкции, за да бъде изпълнена. Това означава, че те не се показват в кода, но скрити в JVM - тя все още ги изпълнява.


Гледайки напред, ние ще демонстрира друго възможно решение. Има много класове в пакета java.util.concurrent за различни употреба многонишковите. Един от тези класове е AtomicInteger. което прави експлоатацията на атомни числа.

обществени клас AtomicCounter # 123;

частен статично окончателно AtomicInteger брояч = нов AtomicInteger # 40; # 41; ;

публично статично вътр GET # 40; # 41; # 123;

се върне обратно. получавам # 40; # 41; ;

публично статично невалидни увеличение # 40; # 41; # 123;

брояч. incrementAndGet # 40; # 41; ;


Сега никъде, което трябва да се добави синхронизация блок.
На другите класове, които го правят по-лесно да се работи с многонишкова, ще кажа в следващата статия.


Синхронизация. Пример за проектиране на многонишков прилагане
В горната част на статията, искам да покажа един пример за малко приложение, както и значението на правилното проектиране потоци.
Да кажем, че имаме 20 файлове с данни. Ние трябва да се чете най-ефективни от тези файлове и показване на данните на екрана. Тези, докато четете, ще бъдат добавени към списъка, а от там се показва.

Налице е клас, който е отговорен за изготвянето на панел, там ще бъде добавянето на артикули, докато четете:

частен PaintPanel панел;

частен невалидни processFile # 40; файл # 41; # 123;

System. навън. ФОРМАТ # 40; "Файл Process% и в% и конец \ Н". файл. getName # 40; # 41. Тема. currentThread # 40; # 41. getName # 40; # 41; # 41; ;

опитвам # 40; FileInputStream ФИС = нов FileInputStream # 40; досие # 41; ;

DataInputStream раз = нов DataInputStream # 40; ФИС # 41; # 41; # 123;

докато # 40; раз. наличен # 40; # 41> 0 # 41; # 123;

Триъгълник триъгълник = триъгълник. чета # 40; раз # 41; ;

панел. addTriangle # 40; триъгълник # 41; ;

Тема. сън # 40; 1 # 41; ;

# 125; улов # 40; IOException | InterruptedException т.е. # 41; # 123;


Сега няма грешка, но обработката на 20 файла отнема около пет минути. Нещо повече, първите файлове се четат бързо и след това се забавя. Опитайте се да разберете защо това се случва.


▌ Вариант 2. Един файл - една нишка

В 20-нишки, че е логично да се предположи, че работата ще се проведе на 20 пъти по-бързо. Това щеше да е, да носи нашата процесор най-малко 20 ядра. В противен случай, ние ще създадем само допълнителен стрес и всички наши данни не могат да се направят много гладко.

списък конци = нов ArrayList <> # 40; файлове. дължина # 41; ;

за # 40; Файл файл. файлове # 41; # 123;

Тема конец = нова Тема # 40; # 40; # 41; -> processFile # 40; досие # 41; # 41; ;

конци. добави # 40; нишка # 41; ;

нишка. начало # 40; # 41; ;

за # 40; Тема нишка. конци # 41; # 123;

нишка. присъединят # 40; # 41; ;

# 125; улов # 40; InterruptedException д # 41; # 123;

Тема. currentThread # 40; # 41. прекъсвам # 40; # 41; ;


Въпреки това, работата в момента е 40 секунди. Това е много време. Същият проблем, че се е забавил работата на първия вариант, забавя всичко сега. Трябва да има начин да се отървете от синхронизирани блока, и този метод е.


▌ Вариант 3: Използване на синхронизирано списък

За да се направи синхронизирано от обичайните списъка, обадете се на метода

Колекции. synchronizedList # 40; списък # 41;


Сега ние получите списък, в който са синхронизирани всички методи. Но, за съжаление, итератор, който се използва в foreach, така че не се включва, за да синхронизирате и ние ще трябва да го увийте в синхронизиран блок, или да го откаже в полза на един прост изброяване на елементи във веригата за.

обществени клас PaintPanelSynchronizedList простира PaintPanel # 123;

частен окончателен Списък триъгълници;

обществен PaintPanelSynchronizedList # 40; вътр ширина, височина вътр # 41; # 123;

супер # 40; ширина, височина # 41; ;

триъгълници = колекции. synchronizedList # 40; новият ArrayList <> # 40; # 41; # 41; ;


▌ Аспект 4. Ограничаване на броя на потоците

Ние може да ограничи броя на нишките, за да се създаде група:

ExecutorService ES = изпълнители. newFixedThreadPool # 40; maxThreads # 41; ;


Сега можете да създадете най-малко сто теми, работещи във всеки един момент ще бъде не повече maxThreads потоци.

Ограничаване на басейна на пет теми

ExecutorService ES = изпълнители. newFixedThreadPool # 40; 5 # 41; ;

за # 40; Файл файл. файлове # 41; # 123;

ове. изпълнявам # 40; # 40; # 41; -> processFile # 40; досие # 41; # 41; ;

ове. изключване # 40; # 41; ;

ове. awaitTermination # 40; 2. TIMEUNIT. МИНУТИ # 41; ;

# 125; улов # 40; InterruptedException д # 41; # 123;

Тема. currentThread # 40; # 41. прекъсвам # 40; # 41; ;


Сега, времето за изпълнение се увеличи до 11 секунди, но предоставянето се осъществява своевременно и ние можем да бъдем сигурни, че ако имахме стотици файлове, системата не получава голям товар.

Най-добрата практика е да се ограничи до басейна нишка на броя процесори в системата:

Изпълнители. newFixedThreadPool # 40; Runtime. getRuntime # 40; # 41. availableProcessors # 40; # 41; # 41; ;


▌ Вариант 5. java.util.concurrent

Свързани статии

Подкрепете проекта - споделете линка, благодаря!