Пулы потоков очень важны для выполнения синхронных и асинхронных процессов. В этой статье показано, как разрабатывать и отслеживать службы пула потоков с помощью Spring. Создание пула потоков было объяснено двумя альтернативными методами.
Используемые технологии:
JDK 1.6.0_21
Spring 3.0.5
Maven 3.0.2
ШАГ 1: СОЗДАТЬ MAVEN ПРОЕКТ
Maven проект создается как показано ниже. (Его можно создать с помощью Maven или IDE Plug-in).
ШАГ 2: БИБЛИОТЕКИ
Spring-зависимости добавляются в pom.xml Maven.
<!-- Spring 3 dependencies -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
Для создания runnable-jar, ниже плагин может быть использован.
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>1.3.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.otv.exe.Application</mainClass> </transformer> <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"> <resource>META-INF/spring.handlers</resource> </transformer> <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"> <resource>META-INF/spring.schemas</resource> </transformer> </transformers> </configuration> </execution> </executions> </plugin>
ШАГ 3: СОЗДАЙТЕ КЛАСС ЗАДАЧИ
Новый класс TestTask создается путем реализации Runnable Interface. Этот класс показывает выполняемые задачи.
package com.otv.task;
import org.apache.log4j.Logger;
/**
* @author onlinetechvision.com
* @since 17 Oct 2011
* @version 1.0.0
*
*/
public class TestTask implements Runnable {
private static Logger log = Logger.getLogger(TestTask.class);
String taskName;
public TestTask() {
}
public TestTask(String taskName) {
this.taskName = taskName;
}
public void run() {
try {
log.debug(this.taskName + " : is started.");
Thread.sleep(10000);
log.debug(this.taskName + " : is completed.");
} catch (InterruptedException e) {
log.error(this.taskName + " : is not completed!");
e.printStackTrace();
}
}
@Override
public String toString() {
return (getTaskName());
}
public String getTaskName() {
return taskName;
}
public void setTaskName(String taskName) {
this.taskName = taskName;
}
}
ШАГ 4: СОЗДАЙТЕ TestRejectedExecutionHandler CLASS
Класс TestRejectedExecutionHandler создается путем реализации интерфейса RejectedExecutionHandler. Если нет свободного потока и переполнения очереди, задачи будут отклонены. Этот класс обрабатывает отклоненные задачи.
package com.otv.handler;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import org.apache.log4j.Logger;
/**
* @author onlinetechvision.com
* @since 17 Oct 2011
* @version 1.0.0
*
*/
public class TestRejectedExecutionHandler implements RejectedExecutionHandler {
private static Logger log = Logger.getLogger(TestRejectedExecutionHandler.class);
public void rejectedExecution(Runnable runnable, ThreadPoolExecutor executor) {
log.debug(runnable.toString() + " : has been rejected");
}
}
ШАГ 5: СОЗДАЙТЕ ITestThreadPoolExecutorService INTERFACE
ITestThreadPoolExecutorService Интерфейс создан.
package com.otv.srv;
import java.util.concurrent.ThreadPoolExecutor;
import com.otv.handler.TestRejectedExecutionHandler;
/**
* @author onlinetechvision.com
* @since 17 Oct 2011
* @version 1.0.0
*
*/
public interface ITestThreadPoolExecutorService {
public ThreadPoolExecutor createNewThreadPool();
public int getCorePoolSize();
public void setCorePoolSize(int corePoolSize);
public int getMaxPoolSize();
public void setMaxPoolSize(int maximumPoolSize);
public long getKeepAliveTime();
public void setKeepAliveTime(long keepAliveTime);
public int getQueueCapacity();
public void setQueueCapacity(int queueCapacity);
public TestRejectedExecutionHandler getTestRejectedExecutionHandler();
public void setTestRejectedExecutionHandler(TestRejectedExecutionHandler testRejectedExecutionHandler);
}
ШАГ 6: СОЗДАЙТЕ TestThreadPoolExecutorService CLASS
Класс TestThreadPoolExecutorService создается путем реализации интерфейса ITestThreadPoolExecutorService. Этот класс создает новый пул потоков.
package com.otv.srv;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import com.otv.handler.TestRejectedExecutionHandler;
/**
* @author onlinetechvision.com
* @since 17 Oct 2011
* @version 1.0.0
*
*/
public class TestThreadPoolExecutorService implements ITestThreadPoolExecutorService {
private int corePoolSize;
private int maxPoolSize;
private long keepAliveTime;
private int queueCapacity;
TestRejectedExecutionHandler testRejectedExecutionHandler;
public ThreadPoolExecutor createNewThreadPool() {
ThreadPoolExecutor executor = new ThreadPoolExecutor(getCorePoolSize(),
getMaxPoolSize(),
getKeepAliveTime(),
TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(getQueueCapacity()),
getTestRejectedExecutionHandler());
return executor;
}
public int getCorePoolSize() {
return corePoolSize;
}
public void setCorePoolSize(int corePoolSize) {
this.corePoolSize = corePoolSize;
}
public int getMaxPoolSize() {
return maxPoolSize;
}
public void setMaxPoolSize(int maxPoolSize) {
this.maxPoolSize = maxPoolSize;
}
public long getKeepAliveTime() {
return keepAliveTime;
}
public void setKeepAliveTime(long keepAliveTime) {
this.keepAliveTime = keepAliveTime;
}
public int getQueueCapacity() {
return queueCapacity;
}
public void setQueueCapacity(int queueCapacity) {
this.queueCapacity = queueCapacity;
}
public TestRejectedExecutionHandler getTestRejectedExecutionHandler() {
return testRejectedExecutionHandler;
}
public void setTestRejectedExecutionHandler(TestRejectedExecutionHandler testRejectedExecutionHandler) {
this.testRejectedExecutionHandler = testRejectedExecutionHandler;
}
}
ШАГ 7: СОЗДАЙТЕ ИНТЕРФЕЙС IThreadPoolMonitorService
IThreadPoolMonitorService Интерфейс создан.
package com.otv.monitor.srv;
import java.util.concurrent.ThreadPoolExecutor;
public interface IThreadPoolMonitorService extends Runnable {
public void monitorThreadPool();
public ThreadPoolExecutor getExecutor();
public void setExecutor(ThreadPoolExecutor executor);
}
ШАГ 8: СОЗДАНИЕ ThreadPoolMonitorService CLASS
Класс ThreadPoolMonitorService создается путем реализации интерфейса IThreadPoolMonitorService. Этот класс контролирует созданный пул потоков.
package com.otv.monitor.srv;
import java.util.concurrent.ThreadPoolExecutor;
import org.apache.log4j.Logger;
/**
* @author onlinetechvision.com
* @since 17 Oct 2011
* @version 1.0.0
*
*/
public class ThreadPoolMonitorService implements IThreadPoolMonitorService {
private static Logger log = Logger.getLogger(ThreadPoolMonitorService.class);
ThreadPoolExecutor executor;
private long monitoringPeriod;
public void run() {
try {
while (true){
monitorThreadPool();
Thread.sleep(monitoringPeriod*1000);
}
} catch (Exception e) {
log.error(e.getMessage());
}
}
public void monitorThreadPool() {
StringBuffer strBuff = new StringBuffer();
strBuff.append("CurrentPoolSize : ").append(executor.getPoolSize());
strBuff.append(" - CorePoolSize : ").append(executor.getCorePoolSize());
strBuff.append(" - MaximumPoolSize : ").append(executor.getMaximumPoolSize());
strBuff.append(" - ActiveTaskCount : ").append(executor.getActiveCount());
strBuff.append(" - CompletedTaskCount : ").append(executor.getCompletedTaskCount());
strBuff.append(" - TotalTaskCount : ").append(executor.getTaskCount());
strBuff.append(" - isTerminated : ").append(executor.isTerminated());
log.debug(strBuff.toString());
}
public ThreadPoolExecutor getExecutor() {
return executor;
}
public void setExecutor(ThreadPoolExecutor executor) {
this.executor = executor;
}
public long getMonitoringPeriod() {
return monitoringPeriod;
}
public void setMonitoringPeriod(long monitoringPeriod) {
this.monitoringPeriod = monitoringPeriod;
}
}
ШАГ 9: СОЗДАЙТЕ СТАРТ КЛАСС
Стартовый класс создан.
package com.otv.start;
import java.util.concurrent.ThreadPoolExecutor;
import org.apache.log4j.Logger;
import com.otv.handler.TestRejectedExecutionHandler;
import com.otv.monitor.srv.IThreadPoolMonitorService;
import com.otv.monitor.srv.ThreadPoolMonitorService;
import com.otv.srv.ITestThreadPoolExecutorService;
import com.otv.srv.TestThreadPoolExecutorService;
import com.otv.task.TestTask;
/**
* @author onlinetechvision.com
* @since 17 Oct 2011
* @version 1.0.0
*
*/
public class Starter {
private static Logger log = Logger.getLogger(TestRejectedExecutionHandler.class);
IThreadPoolMonitorService threadPoolMonitorService;
ITestThreadPoolExecutorService testThreadPoolExecutorService;
public void start() {
// A new thread pool is created...
ThreadPoolExecutor executor = testThreadPoolExecutorService.createNewThreadPool();
executor.allowCoreThreadTimeOut(true);
// Created executor is set to ThreadPoolMonitorService...
threadPoolMonitorService.setExecutor(executor);
// ThreadPoolMonitorService is started...
Thread monitor = new Thread(threadPoolMonitorService);
monitor.start();
// New tasks are executed...
for(int i=1;i<10;i++) {
executor.execute(new TestTask("Task"+i));
}
try {
Thread.sleep(40000);
} catch (Exception e) {
log.error(e.getMessage());
}
for(int i=10;i<19;i++) {
executor.execute(new TestTask("Task"+i));
}
// executor is shutdown...
executor.shutdown();
}
public IThreadPoolMonitorService getThreadPoolMonitorService() {
return threadPoolMonitorService;
}
public void setThreadPoolMonitorService(IThreadPoolMonitorService threadPoolMonitorService) {
this.threadPoolMonitorService = threadPoolMonitorService;
}
public ITestThreadPoolExecutorService getTestThreadPoolExecutorService() {
return testThreadPoolExecutorService;
}
public void setTestThreadPoolExecutorService(ITestThreadPoolExecutorService testThreadPoolExecutorService) {
this.testThreadPoolExecutorService = testThreadPoolExecutorService;
}
}
ШАГ 10: СОЗДАТЬ КЛАСС ПРИЛОЖЕНИЙ
Класс приложения создан. Этот класс запускает приложение.
package com.otv.start;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author onlinetechvision.com
* @since 17 Oct 2011
* @version 1.0.0
*
*/
public class Application {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Starter starter = (Starter) context.getBean("Starter");
starter.start();
}
}
ШАГ 11: СОЗДАТЬ applicationContext.xml
applicationContext.xml создан.
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <!-- Beans Declaration --> <bean id="TestTask" class="com.otv.task.TestTask"></bean> <bean id="ThreadPoolMonitorService" class="com.otv.monitor.srv.ThreadPoolMonitorService"> <property name="monitoringPeriod" value="5" /> </bean> <bean id="TestRejectedExecutionHandler" class="com.otv.handler.TestRejectedExecutionHandler"></bean> <bean id="TestThreadPoolExecutorService" class="com.otv.srv.TestThreadPoolExecutorService"> <property name="corePoolSize" value="1" /> <property name="maxPoolSize" value="3" /> <property name="keepAliveTime" value="10" /> <property name="queueCapacity" value="3" /> <property name="testRejectedExecutionHandler" ref="TestRejectedExecutionHandler" /> </bean> <bean id="Starter" class="com.otv.start.Starter"> <property name="threadPoolMonitorService" ref="ThreadPoolMonitorService" /> <property name="testThreadPoolExecutorService" ref="TestThreadPoolExecutorService" /> </bean> </beans>
ШАГ 12: АЛЬТЕРНАТИВНЫЙ МЕТОД СОЗДАНИЯ РЕЗЬБОВОГО БАССЕЙНА
Класс ThreadPoolTaskExecutor, предоставляемый Spring, также можно использовать для создания пула потоков.
<bean id="threadPoolTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"> <property name="corePoolSize" value="1" /> <property name="maxPoolSize" value="3" /> <property name="queueCapacity" value="3" /> </bean> <bean id="testTaskExecutor" class="TestTaskExecutor"> <constructor-arg ref="threadPoolTaskExecutor" /> </bean>
STEP 13 : BUILD PROJECT
After OTV_Spring_ThreadPool Project is build, OTV_Spring_ThreadPool-0.0.1-SNAPSHOT.jar will be created.
STEP 14 : RUN PROJECT
After created OTV_Spring_ThreadPool-0.0.1-SNAPSHOT.jar file is run, below output logs will be shown :
18.10.2011 20:08:48 DEBUG (TestRejectedExecutionHandler.java:19) - Task7 : has been rejected 18.10.2011 20:08:48 DEBUG (TestRejectedExecutionHandler.java:19) - Task8 : has been rejected 18.10.2011 20:08:48 DEBUG (TestRejectedExecutionHandler.java:19) - Task9 : has been rejected 18.10.2011 20:08:48 DEBUG (TestTask.java:25) - Task1 : is started. 18.10.2011 20:08:48 DEBUG (TestTask.java:25) - Task6 : is started. 18.10.2011 20:08:48 DEBUG (ThreadPoolMonitorService.java:39) - CurrentPoolSize : 3 - CorePoolSize : 1 - MaximumPoolSize : 3 - ActiveTaskCount : 2 - CompletedTaskCount : 0 - TotalTaskCount : 5 - isTerminated : false 18.10.2011 20:08:48 DEBUG (TestTask.java:25) - Task5 : is started. 18.10.2011 20:08:53 DEBUG (ThreadPoolMonitorService.java:39) - CurrentPoolSize : 3 - CorePoolSize : 1 - MaximumPoolSize : 3 - ActiveTaskCount : 3 - CompletedTaskCount : 0 - TotalTaskCount : 6 - isTerminated : false 18.10.2011 20:08:58 DEBUG (TestTask.java:27) - Task6 : is completed. 18.10.2011 20:08:58 DEBUG (TestTask.java:27) - Task1 : is completed. 18.10.2011 20:08:58 DEBUG (TestTask.java:25) - Task3 : is started. 18.10.2011 20:08:58 DEBUG (TestTask.java:25) - Task2 : is started. 18.10.2011 20:08:58 DEBUG (ThreadPoolMonitorService.java:39) - CurrentPoolSize : 3 - CorePoolSize : 1 - MaximumPoolSize : 3 - ActiveTaskCount : 3 - CompletedTaskCount : 2 - TotalTaskCount : 6 - isTerminated : false 18.10.2011 20:08:58 DEBUG (TestTask.java:27) - Task5 : is completed. 18.10.2011 20:08:58 DEBUG (TestTask.java:25) - Task4 : is started. 18.10.2011 20:09:03 DEBUG (ThreadPoolMonitorService.java:39) - CurrentPoolSize : 3 - CorePoolSize : 1 - MaximumPoolSize : 3 - ActiveTaskCount : 3 - CompletedTaskCount : 3 - TotalTaskCount : 6 - isTerminated : false 18.10.2011 20:09:08 DEBUG (TestTask.java:27) - Task2 : is completed. 18.10.2011 20:09:08 DEBUG (TestTask.java:27) - Task3 : is completed. 18.10.2011 20:09:08 DEBUG (TestTask.java:27) - Task4 : is completed. 18.10.2011 20:09:08 DEBUG (ThreadPoolMonitorService.java:39) - CurrentPoolSize : 3 - CorePoolSize : 1 - MaximumPoolSize : 3 - ActiveTaskCount : 0 - CompletedTaskCount : 6 - TotalTaskCount : 6 - isTerminated : false 18.10.2011 20:09:13 DEBUG (ThreadPoolMonitorService.java:39) - CurrentPoolSize : 3 - CorePoolSize : 1 - MaximumPoolSize : 3 - ActiveTaskCount : 0 - CompletedTaskCount : 6 - TotalTaskCount : 6 - isTerminated : false 18.10.2011 20:09:18 DEBUG (ThreadPoolMonitorService.java:39) - CurrentPoolSize : 0 - CorePoolSize : 1 - MaximumPoolSize : 3 - ActiveTaskCount : 0 - CompletedTaskCount : 6 - TotalTaskCount : 6 - isTerminated : false 18.10.2011 20:09:23 DEBUG (ThreadPoolMonitorService.java:39) - CurrentPoolSize : 0 - CorePoolSize : 1 - MaximumPoolSize : 3 - ActiveTaskCount : 0 - CompletedTaskCount : 6 - TotalTaskCount : 6 - isTerminated : false 18.10.2011 20:09:28 DEBUG (TestTask.java:25) - Task10 : is started. 18.10.2011 20:09:28 DEBUG (TestRejectedExecutionHandler.java:19) - Task16 : has been rejected 18.10.2011 20:09:28 DEBUG (TestRejectedExecutionHandler.java:19) - Task17 : has been rejected 18.10.2011 20:09:28 DEBUG (TestRejectedExecutionHandler.java:19) - Task18 : has been rejected 18.10.2011 20:09:28 DEBUG (TestTask.java:25) - Task14 : is started. 18.10.2011 20:09:28 DEBUG (TestTask.java:25) - Task15 : is started. 18.10.2011 20:09:28 DEBUG (ThreadPoolMonitorService.java:39) - CurrentPoolSize : 3 - CorePoolSize : 1 - MaximumPoolSize : 3 - ActiveTaskCount : 3 - CompletedTaskCount : 6 - TotalTaskCount : 12 - isTerminated : false 18.10.2011 20:09:33 DEBUG (ThreadPoolMonitorService.java:39) - CurrentPoolSize : 3 - CorePoolSize : 1 - MaximumPoolSize : 3 - ActiveTaskCount : 3 - CompletedTaskCount : 6 - TotalTaskCount : 12 - isTerminated : false 18.10.2011 20:09:38 DEBUG (TestTask.java:27) - Task10 : is completed. 18.10.2011 20:09:38 DEBUG (TestTask.java:25) - Task11 : is started. 18.10.2011 20:09:38 DEBUG (TestTask.java:27) - Task14 : is completed. 18.10.2011 20:09:38 DEBUG (TestTask.java:27) - Task15 : is completed. 18.10.2011 20:09:38 DEBUG (TestTask.java:25) - Task12 : is started. 18.10.2011 20:09:38 DEBUG (TestTask.java:25) - Task13 : is started. 18.10.2011 20:09:38 DEBUG (ThreadPoolMonitorService.java:39) - CurrentPoolSize : 3 - CorePoolSize : 1 - MaximumPoolSize : 3 - ActiveTaskCount : 3 - CompletedTaskCount : 9 - TotalTaskCount : 12 - isTerminated : false 18.10.2011 20:09:43 DEBUG (ThreadPoolMonitorService.java:39) - CurrentPoolSize : 3 - CorePoolSize : 1 - MaximumPoolSize : 3 - ActiveTaskCount : 3 - CompletedTaskCount : 9 - TotalTaskCount : 12 - isTerminated : false 18.10.2011 20:09:48 DEBUG (TestTask.java:27) - Task11 : is completed. 18.10.2011 20:09:48 DEBUG (TestTask.java:27) - Task13 : is completed. 18.10.2011 20:09:48 DEBUG (TestTask.java:27) - Task12 : is completed. 18.10.2011 20:09:48 DEBUG (ThreadPoolMonitorService.java:39) - CurrentPoolSize : 0 - CorePoolSize : 1 - MaximumPoolSize : 3 - ActiveTaskCount : 0 - CompletedTaskCount : 12 - TotalTaskCount : 12 - isTerminated : true 18.10.2011 20:09:53 DEBUG (ThreadPoolMonitorService.java:39) - CurrentPoolSize : 0 - CorePoolSize : 1 - MaximumPoolSize : 3 - ActiveTaskCount : 0 - CompletedTaskCount : 12 - TotalTaskCount : 12 - isTerminated : true
STEP 15 : DOWNLOAD