concurrency java semaphore
Този урок ще обсъди компоненти на пакета java.util.concurrent като Java Semaphore, Executor Framework, ExecutorService за внедряване на Concurrency в Java:
От предишните ни уроци по Java знаем, че платформата Java поддържа едновременно програмиране от нулата. Основната единица на съвпадение е нишка и ние обсъдихме подробно нишки и многопоточност в Java.
най-добрият безплатен youtube към mp3 конвертор
От Java 5 нататък към платформата на Java беше добавен пакет, наречен ‘java.util.concurrent’. Този пакет съдържа набор от класове и библиотеки, които улесняват програмиста при разработването на едновременни (многонишкови) приложения. Използвайки този пакет, не е нужно да пишем сложни класове, тъй като имаме готови реализации на повечето едновременни концепции.
=> Проверете ВСИЧКИ уроци по Java тук.
В този урок ще обсъдим различните компоненти на пакета java.util.concurrent относно паралелността и многопоточността в Java.
Какво ще научите:
java.util.concurrent пакет
По-долу са изброени различните компоненти на пакета java.util.concurrent относно паралелността и многопоточността в Java. Нека разгледаме всеки компонент в детайли с помощта на прости примери за програмиране. Някои от компонентите ще го направим
обсъждаме са:
- Изпълнителна рамка
- ExecutorService
- ThreadPool
- Извиква се
- Брави - ReentrantLock
- Семафор
- ForkJoinPool
Изпълнителна рамка в Java
Изпълнителната рамка в Java беше пусната с JDK 5. Изпълнителната рамка (java.util.concurrent.Executor) е рамка, която се състои от компоненти, които ни помагат да работим ефективно с множество нишки.
Използвайки Executor Framework, можем да стартираме обекти, които могат да се изпълняват, като използваме вече съществуващите нишки. Не е необходимо да създаваме нови нишки всеки път, когато трябва да изпълняваме обекти.
Изпълнителният API разделя или отделя изпълнението на задача от действителната задача с помощта на Изпълнител . Изпълнителят е центриран върху интерфейса на Изпълнителя и има подинтерфейси, т.е. ExecutorService и класа ThreadPoolExecutor.
По този начин, използвайки Executor, ние просто трябва да създадем Runnable обекти и след това да ги изпратим на изпълнителя, който ги изпълнява.
Някои от най-добрите практики, които трябва да се следват при използване на рамката на Executor, са,
- Трябва да проверим и планираме код, за да прегледаме най-добрите списъци, така че да можем да открием мъртва точка, както и липса в кода.
- Java кодът винаги трябва да се изпълнява срещу инструменти за статичен анализ. Примери на инструментите за статичен анализ са FindBugs и PMD.
- Не трябва да улавяме само изключения, но и грешките в многонишковите програми.
Сега да обсъдим компонентите на Executor Framework в Java.
Изпълнител
Изпълнителят може да бъде дефиниран като интерфейс, използван за представяне на обект, който изпълнява предоставените му задачи. Дали задачата трябва да се изпълни на текуща или нова нишка зависи от точката, от която е инициирано извикването, което допълнително зависи от изпълнението.
Така че, използвайки Executor, можем да отделим задачите от действителната задача и след това да ги изпълним асинхронно.
Изпълнението на задачата с помощта на Executor обаче не е необходимо да бъде асинхронно. Изпълнителите могат също да извикват задачата незабавно, като използват извикваща нишка.
Дадено по-долу е примерна част от код за създаване на екземпляр на изпълнител:
public class Invoker implements Executor { @Override public void execute (Runnable r_interface) { r_interface.run(); } }
След като създаде извикващото устройство, както е показано по-горе, можем да го използваме за изпълнение на задачата, както следва.
public void execute () { Executor executor = new Invoker (); executor.execute ( () -> { //perform task }); }
Имайте предвид, че ако задачата не е приета от изпълнителя, тя хвърля RejectedExecutionException.
ExecutorService
ExecutorService (java.util.concurrent.ExecutorService) планира подадените задачи според наличността на нишки и също поддържа опашка от памет. ExecutorService действа като цялостно решение за асинхронна обработка на задачи.
За да използваме ExecutorService в кода, ние създаваме Runnable клас. ExecutorService поддържа пул от нишки и също присвоява задачите на нишките. Задачите също могат да се редят на опашка, в случай че нишката не е налична.
По-долу е даден прост пример за ExecutorService.
import java.util.concurrent.*; public class Main { public static void main(String() args) { //create ExecutorService instance with 10 threads ExecutorService executor_Service = Executors.newFixedThreadPool(10); //assign the service to Runnable instance executor_Service.execute(new Runnable() { @Override public void run() { //print the message System.out.println('Simple Example of ExecutorService!!!'); } }); //shutdown executorService executor_Service.shutdown(); } }
Изход
В горната програма създаваме прост екземпляр ExecutorService с пул от нишки, състоящ се от 10 нишки. След това се присвоява на екземпляра Runnable и се изпълнява за отпечатване на горното съобщение. След отпечатване на съобщението ExecutorService се изключва.
Тема басейн
Пул от нишки в Java е група работни нишки, които могат да се използват многократно и да им се задават задачи.
Пул нишки съдържа група нишки с фиксиран размер. Всяка нишка се изтегля от пула от нишки и й се възлага задача от доставчика на услуги. След като присвоената задача приключи, нишката се дава отново в пула от нишки.
Thread pool е предимство, тъй като не е необходимо да създаваме нова нишка всеки път, когато задачата е налична, като по този начин производителността се подобрява. Използва се в приложения в реално време, които използват Servlet и JSP, където пуловете от нишки се използват за обработка на заявки.
В многонишковите приложения Thread Pool спестява ресурси и помага да се задържи паралелизмът в предварително определени граници.
Долната програма Java демонстрира пула от нишки в Java.
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; class WorkerThreadClass implements Runnable { private String message; //thread class constructor public WorkerThreadClass(String s){ this.message=s; } //run method for thread public void run() { System.out.println(' Start: '+message); processmessage(); //sleep between start and end System.out.println(' End: '+ message); } //processmessage method => sleeps the thread for 2 sec private void processmessage() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } public class Main { public static void main(String() args) { //create a ExecutorService instance ExecutorService executor = Executors.newFixedThreadPool(5);//creating a pool of 5 threads //create thread instances and execute them for (int i = 0; i <5; i++) { Runnable workerThrd = new WorkerThreadClass('Thread_' + i); executor.execute(workerThrd);//calling execute method of ExecutorService } //shutdown ExecutorService executor.shutdown(); while (!executor.isTerminated()) { } System.out.println('Finished all threads'); } }
Изход
В горните програми има пул от нишки от 5 нишки, които са създадени с помощта на метода “newFixedThreadPool”. След това нишките се създават и добавят към пула и се присвояват на ExecutorService за изпълнение.
Извиква се в Java
Вече знаем, че можем да създаваме нишки, използвайки два подхода. Единият подход е чрез разширяване на класа Thread, докато вторият подход е чрез внедряване на Runnable интерфейс.
Въпреки това, нишките, създадени с помощта на Runnable интерфейс, нямат една функция, т.е.не връща резултат, когато нишката е прекратена или run () завърши изпълнението. Тук в картината влиза интерфейсът Callable.
Използвайки Callable интерфейс, ние дефинираме задача, така че да върне резултат. Той може също да създаде изключение. Интерфейсът Callable е част от пакета java.util.concurrent.
Интерфейсът Callable осигурява метод call (), който е на подобни линии като метода run (), предоставен от интерфейса Runnable, с единствената разлика, че методът call () връща стойност и изхвърля проверено изключение.
Методът call () на интерфейса Callable има следния прототип.
public Object call () throws Exception;
Тъй като методът call () връща обект, основната нишка трябва да знае това.
Следователно връщаната стойност трябва да се съхранява в друг обект, известен на основната нишка. Тази цел се обслужва чрез използване на обект „Бъдеще“. Обект Future е обект, който съдържа резултата, върнат от нишка. Или с други думи, той ще задържи резултата, когато Callable се върне.
Callable капсулира задача, която трябва да се изпълнява в друга нишка. Обект Future съхранява резултата, върнат от различна нишка.
Извикваем интерфейс не може да се използва за създаване на нишка. Трябва ни Runnable, за да създадем нишка. След това за съхраняване на резултата е необходим обект Future. Java предоставя конкретен тип, наречен „FutureTask“, който съчетава функционалността чрез внедряване както на Runnable, така и на Future.
Ние създаваме FutureTask, като предоставяме конструктор с Callable. След това този обект FutureTask се дава на конструктора на класа Thread, за да създаде Thread обект.
По-долу е дадена Java програма, която демонстрира интерфейса Callable и обекта Future. Ние също използваме обекта FutureTask в тази програма.
Както вече споменахме, в програмата създаваме клас, който реализира Callable интерфейс с заменен метод call (). В основния метод създаваме 10 обекта FutureTask. Всеки конструктор на обекти има обект на клас Callable като свой аргумент. Тогава обектът FutureTask се свързва с екземпляр на нишка.
Следователно косвено създаваме нишка, използвайки обект на интерфейс Callable.
import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; //create a class implementing Callable interface class CallableDemo implements Callable { //define call () method public Object call() throws Exception { Random generator = new Random(); Integer randomNumber = generator.nextInt(10); Thread.sleep(randomNumber * 1000); return randomNumber; } } public class Main { public static void main(String() args) throws Exception { // Array of FutureTask objects FutureTask() randomNumberTasks = new FutureTask(10); for (int i = 0; i <10; i++) { Callable callable = new CallableDemo(); // Create the FutureTask with Callable class randomNumberTasks(i) = new FutureTask(callable); // create thread with FutureTask Thread t = new Thread(randomNumberTasks(i)); //start the thread t.start(); } System.out.println('The contents of FutureTask objects:'); for (int i = 0; i < 10; i++) { // get() contents of FutureTask System.out.print(randomNumberTasks(i).get() + ' '); } } }
Изход
Както е показано в горната програма, методът call () на Callable, който е заменен в класа, изпълняващ Callable, генерира произволни числа. След като нишката е стартирана, тя показва тези произволни числа.
Също така използваме обекти FutureTask в основната функция. Тъй като реализира интерфейса Future, не е необходимо да съхраняваме резултатите в Thread обектите. По същия начин можем да отменим задачата, да проверим дали тя е изпълнена или завършена, а също така да получим резултата с помощта на обекта FutureTask.
ReentrantLock в Java
Обсъдихме подробно синхронизирането на нишки, използвайки синхронизираната ключова дума в нашия последен урок. Използването на синхронизираната дума за синхронизация на нишки е основният метод и е донякъде твърд.
Използвайки синхронизираната ключова дума, нишката може да се заключи само веднъж. Също така, след като една нишка излезе от синхронизирания блок, следващата нишка приема ключалката. Няма опашка за чакане. Тези проблеми могат да причинят глад на някаква друга нишка, тъй като тя може да няма достъп до ресурсите за дълго време.
За да се справим с тези проблеми, се нуждаем от гъвкав метод за синхронизиране на нишките. „Reentrant Locks“ е този метод в Java, който осигурява синхронизация с много по-голяма гъвкавост.
Класът “ReentrantLock” реализира заключвания Reentrant и е част от пакета “import java.util.concurrent.locks”. Класът ReentrantLock осигурява синхронизация на метода за достъп до споделени ресурси. Класовете също имат методи за заключване и отключване за заключване / отключване на ресурси при достъп до нишки.
Една особена характеристика на ReentrantLock е, че нишката може да заключва споделения ресурс повече от веднъж, използвайки ReentrantLock. Той осигурява брой задържания, който е зададен на едно, когато нишката заключи ресурса.
Нишката може да влезе отново и да осъществи достъп до ресурса преди отключване. Всеки път, когато нишката осъществява достъп до ресурса чрез заключване Reentrant, броят на задържанията се увеличава с един. За всяко отключване броят на задържанията се намалява с един.
Когато броят на задържанията достигне 0, споделеният ресурс се отключва.
Класът ReentrantLock също предоставя параметър за справедливост, който е логическа стойност, която може да бъде предадена с конструктора на ключалката. Когато параметърът на справедливост е зададен на true, тогава, когато една нишка освободи заключването, заключването се предава на най-дълго чакащата нишка. Това предотвратява гладуването.
Бравите Reentrant могат да се използват, както следва:
return_type method_name() { reentrantlock.lock(); try { //Do some work } catch(Exception e) { e.printStackTrace(); } finally { reentrantlock.unlock(); } }
Обърнете внимание, че декларацията за отключване за ReentrantLock винаги е в блока final. Това гарантира, че заключването се освобождава, дори ако се изведе изключение.
Нека внедрим програма Java, за да разберем ReentrantLock.
import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.*; import java.util.concurrent.locks.ReentrantLock; //thread class that implements Runnable interface class ThreadClass implements Runnable { String task_name; //define ReentrantLock object ReentrantLock thrd_lck; //ThreadClass constructor initialized lock and task name public ThreadClass(ReentrantLock r_lock, String t_name) { thrd_lck = r_lock; task_name = t_name; } //thread run () method public void run() { boolean bool_val = false; while (!bool_val) { //check for Outer Lock boolean tryLock_val = thrd_lck.tryLock(); // if lock is free, do the following if(tryLock_val) { try { for(int i=0;i<=6;i++) { if(i>=2) { thrd_lck.lock(); Thread thread_one = new Thread(); System.out.println('Thread Created.....'); if(i==3) { thread_one.setName('Maint Thread2'); System.out.println('Thread Created.....'); } } if(i==4) thrd_lck.unlock(); break; } System.out.println('ReentrantLock=>Is locked after sleep(1500) : ' + thrd_lck.isLocked()); System.out.println('Work done for task : ' + task_name ); bool_val = true; } catch(Exception e) { e.printStackTrace(); } } } } } public class Main { public static void main(String() args) { //define ReentrantLock lock object and service pool ReentrantLock reentrant_lock = new ReentrantLock(); ExecutorService pool = Executors.newFixedThreadPool(2); //create thread instance and pass lock and task name Runnable worker_thread = new ThreadClass(reentrant_lock, 'ThreadJob'); //execute the thread in exec pool pool.execute(worker_thread); //shut down the pool pool.shutdown(); } }
Изход
В горната програма създадохме нишка и използвахме ReentrantLock за нея. Използване на ReentrantLock може да се осъществи достъп до споделения ресурс.
Семафор в Java
Следващият метод за синхронизация на нишки е чрез използване на Semaphore. Използвайки тази конструкция, наречена семафор, достъпът до споделен ресурс се контролира чрез брояч. Сигналите се изпращат между нишките, за да можем да опазим критичния участък и също така да избегнем пропуснатите сигнали.
Семафорът може да бъде дефиниран като променлива, която се използва за управление на едновременни процеси чрез синхронизиране на тези процеси. Семафорите също се използват за синхронизиране на достъпа до споделения ресурс и по този начин се избягва състезателно състояние. Разрешението, дадено на нишка за достъп до споделения ресурс от семафор, също се нарича разрешение.
В зависимост от това какви функции изпълняват, семафорите могат да бъдат разделени на два типа:
# 1) Двоичен семафор: Двоичен семафор се използва за синхронизиране на едновременни процеси и осъществяване на взаимно изключване. Двоичният семафор приема само две стойности, т.е. 0 и 1.
# 2) Преброяване на семафор: Преброяващият семафор има стойност, която показва броя на процесите, които могат да влязат в критичната секция. Във всеки момент стойността показва максималния брой процеси, които влизат в критичната секция.
И така, как работи семафорът?
Работата на семафор може да бъде обобщена в следните стъпки:
- Ако броят на семафорите> 0, това означава, че нишката има разрешение за достъп до критична секция и след това броят се намалява.
- В противен случай нишката се блокира, докато се получи разрешението.
- Когато нишката приключи с достъпа до споделения ресурс, разрешението се освобождава и броят на семафорите се увеличава, така че друга нишка може да повтори горните стъпки и да получи разрешението.
Горните стъпки от работата на семафорите могат да бъдат обобщени в долната блок-схема.
В Java не е необходимо да прилагаме нашия семафор, но той предоставя a Семафор клас, който реализира семафорната функционалност. Класът Semaphore е част от java.util.concurrent пакет.
Класът Semaphore предоставя следните конструктори, с помощта на които можем да създадем семафорен обект:
Semaphore (int num_value) Semaphore (int num_value, boolean how)
Тук,
num_value => начална стойност на броя разрешения, която определя броя нишки, които имат достъп до споделения ресурс.
как => задава реда, в който на нишките ще се предоставят разрешения (как = вярно). Ако как = невярно, тогава не се спазва такъв ред.
Сега ще внедрим програма Java, която ще демонстрира семафора, който се използва за управление на споделения достъп до ресурси и предотвратяване на състоянието на състезанието.
import java.util.concurrent.*; //class for shared resource class SharedRes { static int count = 0; } class ThreadClass extends Thread { Semaphore sem; String threadName; public ThreadClass(Semaphore sem, String threadName) { super(threadName); this.sem = sem; this.threadName = threadName; } @Override public void run() { // Thread T1 processing if(this.getName().equals('T1')) { System.out.println('Start: ' + threadName); try { System.out.println(threadName + ' :waiting for a permit.'); // acquire the permit sem.acquire(); System.out.println(threadName + ':Acquired permit'); // access shared resource for(int i=0; i <5; i++) { SharedRes.count++; System.out.println(threadName + ': ' + SharedRes.count); Thread.sleep(10); } } catch (InterruptedException exc) { System.out.println(exc); } // Release the permit. System.out.println(threadName + ':Released the permit'); sem.release(); } // Thread T2 processing else { System.out.println('Start: ' + threadName); try { System.out.println(threadName + ':waiting for a permit.'); // acquire the lock sem.acquire(); System.out.println(threadName + ':Acquired permit'); // process the shared resource for(int i=0; i < 5; i++) { SharedRes.count--; System.out.println(threadName + ': ' + SharedRes.count); Thread.sleep(10); } } catch (InterruptedException exc) { System.out.println(exc); } // Release the permit. System.out.println(threadName + ':Released the permit.'); sem.release(); } } } public class Main { public static void main(String args()) throws InterruptedException { //create Semaphore=> #permits = 1 Semaphore sem = new Semaphore(1); // Create thread instances T1 & T2 //T1=> Increments the count; T2=> Decrements the count ThreadClass thread1 = new ThreadClass(sem, 'T1'); ThreadClass thread2 = new ThreadClass(sem, 'T2'); // start T1 & T2 thread1.start(); thread2.start(); // Wait T1 & T2 thread1.join(); thread2.join(); System.out.println('count: ' + SharedRes.count); // display final count. } }
Изход
Тази програма декларира клас за споделения ресурс. Той също така декларира клас нишка, в който имаме семафорна променлива, която е инициализирана в конструктора на класа.
В метода overridden run () на класа Thread се извършва обработка на екземпляр на нишка, при който нишката придобива разрешението, осъществява достъп до споделен ресурс и след това освобождава разрешението.
В основния метод декларирахме два екземпляра на нишки. След това и двете нишки се стартират и след това изчакват с помощта на метода на присъединяване. Накрая се показва броят, т.е. 0, което показва, че и двете нишки са завършили със споделения ресурс.
Разклонете се и се присъединете към Java
Рамката fork / join беше представена за първи път в Java 7. Тази рамка се състои от инструменти, които могат да ускорят паралелната обработка. Той използва всички налични процесорни ядра в системата и изпълнява задачата. Рамката fork / join използва подхода „разделяй и владей“.
Основната идея зад рамката Fork / Join е, че първата рамка „Forks“, т.е. рекурсивно разбива задачата на по-малки отделни подзадачи, докато задачите станат атомни, за да могат да се изпълняват асинхронно.
След като направите това, задачите се „обединяват“, т.е. всички подзадачи се обединяват рекурсивно в една задача или върната стойност.
Рамката fork / join има набор от нишки, известни като „ForkJoinPool“. Този пул управлява типа „ForkJoinWorkerThread“ работни нишки, като по този начин осигурява ефективна паралелна обработка.
ForkJoinPool управлява работните нишки и също така ни помага да получим информация относно производителността и състоянието на пула от нишки. ForkJoinPool е изпълнение на “ExecutorService”, което обсъдихме по-горе.
За разлика от работните нишки, ForkJoinPool не създава отделна нишка за всяка подзадача. Всяка нишка във ForkJoinPool поддържа своето deque (двойна опашка) за съхраняване на задачи.
Deque действа като балансиране на натоварването на нишката и прави това с помощта на 'алгоритъм за кражба на работа', който е описан по-долу.
Алгоритъм за кражба на работа
Можем да определим алгоритъма за кражба на работа с прости думи като „Ако нишката е безплатна,„ открадне “работата от заети нишки“.
Работна нишка винаги ще получава задачите от своето deque. Когато всички задачи в deque са изчерпани и deque е празен, работната нишка ще вземе задача от опашката на друг deque или от „глобалната опашка за влизане“.
По този начин възможността нишките да се състезават за задачи е сведена до минимум и също така е намален броят пъти, в които нишката трябва да търси работа. Това е така, защото нишката вече има най-голямата част от наличната работа и я е завършила.
И така, как можем да използваме ForkJoinPool в програма?
Общата дефиниция на ForkJoinPool е както следва:
public class ForkJoinPool extends AbstractExecutorService
Класът ForkJoinPool е част от пакета “java.util.concurrent”.
В Java 8 създаваме екземпляр на ForkJoinPool, използвайки неговия статичен метод “common-pool ()”, който предоставя препратка към общия пул или пула от нишки по подразбиране.
ForkJoinPool commonPool = ForkJoinPool.commonPool ();
В Java 7 създаваме екземпляр на ForkJoinPool и го присвояваме на полето на полезния клас, както е показано по-долу.
public static ForkJoinPool forkJoinPool = new ForkJoinPool(2);
Горната дефиниция показва, че пулът има ниво на паралелизъм 2, така че пулът ще използва 2 процесорни ядра.
За достъп до горния пул можем да дадем следното изявление.
ForkJoinPool forkJoinPool = PoolUtil.forkJoinPool;
Основният тип за задачите на ForkJoinPool е “ForkJoinTask”. Трябва да разширим един от неговите подкласове, т.е. за невалидни задачи, RecursiveAction и за задачи, връщащи стойност, RecursiveTask. И двата разширени класа предоставят абстрактен метод compute (), в който дефинираме логиката на задачата.
По-долу е даден пример за демонстриране на ForkJoinPool.
import java.util.ArrayList; import java.util.List; import java.util.concurrent.*; //class declaration for ForkJoinPool tasks class FJPoolTask extends RecursiveAction { private long Load = 0; public FJPoolTask(long Load) { this.Load = Load; } @Override protected void compute() { //if threshold is reached, break tasks into smaller tasks List subtasks = new ArrayList(); subtasks.addAll(createSubtasks()); for(RecursiveAction subtask : subtasks){ subtask.fork(); } } //create subtasks private List createSubtasks() { List sub_tasks =new ArrayList(); FJPoolTask sub_task1 = new FJPoolTask(this.Load / 2); FJPoolTask sub_task2 = new FJPoolTask(this.Load / 2); FJPoolTask sub_task3 = new FJPoolTask(this.Load / 2); sub_tasks.add(sub_task1); sub_tasks.add(sub_task2); sub_tasks.add(sub_task3); return sub_tasks; } } public class Main { public static void main(final String() arguments) throws InterruptedException { //get count of available processors int proc = Runtime.getRuntime().availableProcessors(); System.out.println('Processors available:' +proc); //declare forkJoinPool ForkJoinPool Pool = ForkJoinPool.commonPool(); System.out.println(' Active Threads (Before invoke):' +Pool.getActiveThreadCount()); //Declare ForkJoinPool task object FJPoolTask t = new FJPoolTask(400); //submit the tasks to the pool Pool.invoke(t); System.out.println(' Active Threads (after invoke):' +Pool.getActiveThreadCount()); System.out.println('Common Pool Size :' +Pool.getPoolSize()); } }
Изход
В горната програма намираме броя на активните нишки в системата преди и след извикване на метода “invoke ()”. Методът invoke () се използва за изпращане на задачите в пула. Също така намираме броя на наличните процесорни ядра в системата.
често задавани въпроси
В # 1) Какво представлява Java Util Concurrent?
Отговор: Пакетът „java.util.concurrent“ е набор от класове и интерфейси, предоставени от Java за улесняване разработването на едновременни (многонишкови) приложения. Използвайки този пакет, ние можем директно да използваме интерфейса и класовете, както и API, без да се налага да пишем нашите класове.
В # 2) Кое от изброените са едновременни внедрения, налични в java.util. едновременен пакет?
Отговор: На високо ниво пакетът java.util.concurrent съдържа помощни програми като Изпълнители, Синхронизатори, Опашки, Времена и Колективни колекции.
В # 3) Какво е бъдещата Java?
Отговор: Обект на бъдеще (java.util.concurrent.Future) се използва за съхраняване на резултата, върнат от нишка, когато е изпълнен Callable интерфейс.
В # 4) Какво е безопасно за нишки в Java?
Отговор: Безопасен за нишки код или клас в Java е код или клас, които могат да се споделят в многонишка или едновременна среда без никакви проблеми и дават очаквани резултати.
В # 5) Какво представлява синхронизираната колекция в Java?
Отговор: Синхронизираната колекция е безопасна за нишки колекция. Методът синхронизирана колекция () на клас java.util.Collections връща синхронизирана (безопасна за нишките) колекция.
Заключение
С този урок завършихме темата за многопоточност и едновременност в Java. Обсъдихме подробно многопоточността в предишните ни уроци. Тук обсъдихме паралелността и изпълнението, свързано с паралелността и многопоточността, които са част от пакета java.util.concurrent.
Обсъдихме още два метода за синхронизация, семафори и ReentrantLock. Също така обсъдихме ForkJoinPool, който се използва за изпълнение на задачите, като ги разделя на по-прости задачи и след това в крайна сметка се присъединява към резултата.
Пакетът java.util.concurrent също така поддържа рамката Executor и изпълнителите, които ни помагат да изпълняваме нишки. Също така обсъдихме изпълнението на пула от нишки, което се състои от нишки за многократна употреба, които се връщат в пула, когато изпълнението приключи.
Обсъдихме друг интерфейс, подобен на Runnable, който също ни помага да върнем резултат от нишката и обекта Future, използван за съхраняване на получения резултат от нишката.
=> Внимавайте тук за простия сериал за обучение на Java.
Препоръчително четене
- Thread.Sleep () - Метод на Sleep Thread () в Java с примери
- Разполагане на Java: Създаване и изпълнение на Java JAR файл
- Основи на Java: Синтаксис на Java, клас Java и основни концепции на Java
- Java виртуална машина: Как JVM помага при стартирането на Java приложение
- Модификатори на достъп в Java - Урок с примери
- Синхронизирано с Java: Какво представлява синхронизация на нишки в Java
- Урок за JAVA за начинаещи: 100+ практически ръководства за Java видео
- Java Integer и Java BigInteger клас с примери