Когато разработваме многонишково приложение, обикновено трябва да се занимаваме с организиране на работата на нишките. Колкото по-голямо е нашето приложение и колкото повече нишки са ни необходими за многонишкови задачи, толкова повечеРаботимобекти, които създаваме.

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

Тук на помощ ни идват пул от нишки и ThreadPoolExecutor .

Пулът от нишки е набор от предварително инициализирани нишки. Размерът му може да бъде фиксиран or променлив.

Ако има повече задачи, отколкото нишки, тогава задачите чакат в опашка със задачи. N-тата нишка в пула взема задача от опашката и след като тя бъде изпълнена, нишката взима нова задача от опашката. След като всички задачи в опашката бъдат изпълнени, нишките остават активни и чакат нови задачи. Когато се появят нови задачи, нишките също започват да ги изпълняват.

ThreadPoolExecutor

Започвайки с Java 5, рамката Executor придоби многопоточно решение. Като цяло има много компоненти и целта му е да ни помогне да управляваме ефективно опашки и пулове от нишки.

Основните интерфейси са Executor и ExecutorService .

Executor е интерфейс с един метод void execute (Runnable runnable).

Когато предавате задача на имплементация на този метод, знайте, че тя ще се изпълнява асинхронно в бъдеще.

ExecutorService — Интерфейс, който разширява интерфейса на Executor , добавяйки възможности за изпълнение на задачи. Той също така има методи за прекъсване на изпълнявана задача и прекратяване на пула от нишки.

ThreadPoolExecutor имплементира интерфейсите Executor и ExecutorService и разделя създаването на задача от изпълнението на задача. Трябва да внедрим Runnable обекти и да ги изпратим на изпълнител. След това ThreadPoolExecutorе отговорен за изпълнението на задачите и създаването и работата с нишки .

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

ThreadPoolExecutor има 4 конструктора:


ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime, 
TimeUnit unit, 
BlockingQueue<Runnable> workQueue)
    

ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler)
    

ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime, 
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory)
    

ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime, 
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory, 
RejectedExecutionHandler handler)
    

Конструкторът ThreadPoolExecutor има следните параметри:

corePoolSize Този параметър показва колко нишки ще бъдат готови (стартирани) при стартиране на услугата изпълнител.
максимален размер на басейна Максималният брой нишки, които една изпълнителна услуга може да създаде.
keepAliveTime Времето, през което освободена нишка ще продължи да живее, преди да бъде унищожена, ако броят на нишките е по-голям отcorePoolSize. Единиците за време са посочени в следващия параметър.
мерна единица Единици за време (часове, minutesи, секунди, мorсекунди и др.).
workQueue Внедряване на опашка за задачи.
манипулатор Манипулатор за задачи, които не могат да бъдат изпълнени.
threadFactory Обект, който създава нови нишки при поискване. Използването на фабрики за нишки прави повикванията към нов хардуер за нишки независими, позволявайки на applicationsта да използват специални подкласове на нишки, приоритети и т.н.

Създаване на ThreadPoolExecutor

Класът на помощната програма Executors може да опрости създаването на ThreadPoolExecutor . Методите на този полезен клас ни помагат да подготвим aThreadPoolExecutorобект.

newFixedThreadPool — Създава набор от нишки, който използва повторно фиксиран брой нишки за изпълнение на произволен брой задачи.

ExecutorService executor = Executors.newFixedThreadPool(10);
                    
newWorkStealingPool — Създава набор от нишки, където броят на нишките е equals на броя процесорни ядра, достъпни за JVM. Нивото на едновременност по подразбиране е едно. Това означава, че толкова нишки ще бъдат създадени в пула, колкото има CPU ядра, достъпни за JVM. Ако нивото на едновременност е 4, тогава предадената стойност се използва instead of броя на ядрата.

ExecutorService executor = Executors.newWorkStealingPool(4);
                    
newSingleThreadExecutor — Създава пул с една нишка за изпълнение на всички задачи.

ExecutorService executor = Executors.newSingleThreadExecutor();
                    
newCachedThreadPool — Създава набор от нишки, който създава нови нишки, ако е необходимо, но използва повторно създадени преди това нишки, когато са налични.

ExecutorService executor = Executors.newCachedThreadPool();
                    
newScheduledThreadPool — Създава набор от нишки, който може да планира команди за изпълнение след дадено забавяне or периодично.

ScheduledExecutorService executor = Executors.newScheduledThreadPool(10);
                    

Ще разгледаме всеки тип басейн в следващите уроци.