基于线程池实现多线程任务
来源:互联网 发布:java jdk7.0 64位下载 编辑:程序博客网 时间:2024/06/10 15:33
首先,让我们问一个问题,为什么要使用线程池?很多时候,我们使用多线程来执行任务的时候都是这样一个场景:每新建一个任务就对应地创建一个线程,而往往每个任务在很短的时间内就结束了,导致线程的创建和销毁频繁发生,这会降低系统的效率。于是自然地我们就会想到,是不是可以像连接池复用连接一样复用线程呢?即,每完成一个任务,线程并不销毁,而是等下一个任务到来。答案当然是肯定的。
一,Java线程池
1,ThreadPoolExecutor
ThreadPoolExecutor是线程池任务执行器。其继承链为
ThreadPoolExecutor extends AbstractExecutorService implements ExecutorServiceextendsExecutor
ThreadPoolExecutor的几个重要构造参数包括以下:
1)corePoolSize:核心池尺寸,当池大小小于corePoolSize时,就新建线程来执行任务。当池大小等于corePoolSize时,就将任务放进workQueue阻塞队列。池子中的空闲线程去队列中获取任务来执行。
2)maximumPoolSize:最大池尺寸,当队列已经满了,就新建线程入池来处理请求,但是线程数量不能超过最大池尺寸。
3)keepAliveTime:线程存活时间,决定当一个线程空闲了多长时间后被销毁。只有在线程池尺寸大于corePoolSize时才起作用。
4)unit:时间单位,有7种选择:
TimeUnit.DAYS; //天
TimeUnit.HOURS; //小时
TimeUnit.MINUTES; //分钟
TimeUnit.SECONDS; //秒
TimeUnit.MILLISECONDS; //毫秒
TimeUnit.MICROSECONDS; //微妙
TimeUnit.NANOSECONDS; //纳秒
5)workQueue:阻塞队列,用来存储待执行的任务。声明类型为BlockingQueue<Runnable>,有以下几种选择:
ArrayBlockingQueue
基于数组,先进先出,必须指定大小
LinkedBlockingQueue
基于链表,先进先出,如未指定大小,则为Integer.MAX_VALUE
SynchronousQueue
没有尺寸的概念,不会保存提交的任务,而是将直接新建一个线程来执行新来的任务
PriorityBlockingQueue
其存储的对象必须实现Comparable接口,队列根据compare接口方法确定任务的优先级
常用的是LinkedBlockingQueue和SynchronousQueue
6)threadFactory,线程工厂,用来创建线程。
7)handler,拒绝处理任务时的策略,包括
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:丢弃任务,不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
ThreadPoolExecutor的几个重要方法
1)execute()
向线程池提交任务,交由线程池来执行
2)submit()
同样是向线程池提交任务,其内部调用了execute(),区别是,会返回一个FutureTask实例
3)shutdown()
等任务都执行完毕后关闭线程池,并且拒绝接受新的任务
4)shutdownNow()
停止正在执行的任务,立刻关闭线程池,拒绝接受新的任务
5)isTerminated()
检查线程池是否已关闭
代码示例:
任务类
package com.wxy.popcorn.threadpool;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class Task implements Runnable { private Logger logger = LoggerFactory.getLogger(getClass()); private String tName; public Task(String tName) { this.tName = tName; } public void run() { logger.info("{} is executing the {}", Thread.currentThread().getName(), tName); }}任务执行器
package com.wxy.popcorn.threadpool;import java.util.concurrent.ArrayBlockingQueue;import java.util.concurrent.Executors;import java.util.concurrent.ThreadPoolExecutor;import java.util.concurrent.TimeUnit;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class TaskExecutor { private Logger logger = LoggerFactory.getLogger(getClass()); private int executeTimes; private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(4, 10, 2000L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(100), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); public TaskExecutor(int executeTimes) { this.executeTimes = executeTimes; } public void executeTasks() { for (int i=0; i< executeTimes; i++) { threadPoolExecutor.execute(new Task("task"+i)); } threadPoolExecutor.shutdown(); while (true) { if (threadPoolExecutor.isTerminated()) { logger.info("==========End to execute the tasks=========="); break; } } }}测试类
package com.wxy.popcorn.threadpool;import org.junit.Test;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class TaskExecutorTest { private Logger logger = LoggerFactory.getLogger(getClass()); @Test public void test() { logger.info("==========Begin to execute tasks=========="); new TaskExecutor(20).executeTasks(); }}测试结果
2017-12-25 23:15:28.735 [main] INFO [TaskExecutorTest.java:12] ==========Begin to execute tasks==========2017-12-25 23:15:28.753 [pool-2-thread-3] INFO [Task.java:15] pool-2-thread-3 is executing the task22017-12-25 23:15:28.753 [pool-2-thread-1] INFO [Task.java:15] pool-2-thread-1 is executing the task02017-12-25 23:15:28.753 [pool-2-thread-2] INFO [Task.java:15] pool-2-thread-2 is executing the task12017-12-25 23:15:28.756 [pool-2-thread-3] INFO [Task.java:15] pool-2-thread-3 is executing the task42017-12-25 23:15:28.756 [pool-2-thread-1] INFO [Task.java:15] pool-2-thread-1 is executing the task52017-12-25 23:15:28.756 [pool-2-thread-4] INFO [Task.java:15] pool-2-thread-4 is executing the task32017-12-25 23:15:28.756 [pool-2-thread-2] INFO [Task.java:15] pool-2-thread-2 is executing the task62017-12-25 23:15:28.756 [pool-2-thread-3] INFO [Task.java:15] pool-2-thread-3 is executing the task72017-12-25 23:15:28.757 [pool-2-thread-1] INFO [Task.java:15] pool-2-thread-1 is executing the task82017-12-25 23:15:28.757 [pool-2-thread-4] INFO [Task.java:15] pool-2-thread-4 is executing the task92017-12-25 23:15:28.757 [pool-2-thread-2] INFO [Task.java:15] pool-2-thread-2 is executing the task102017-12-25 23:15:28.757 [pool-2-thread-3] INFO [Task.java:15] pool-2-thread-3 is executing the task112017-12-25 23:15:28.757 [pool-2-thread-1] INFO [Task.java:15] pool-2-thread-1 is executing the task122017-12-25 23:15:28.757 [pool-2-thread-4] INFO [Task.java:15] pool-2-thread-4 is executing the task132017-12-25 23:15:28.757 [pool-2-thread-2] INFO [Task.java:15] pool-2-thread-2 is executing the task142017-12-25 23:15:28.757 [pool-2-thread-3] INFO [Task.java:15] pool-2-thread-3 is executing the task152017-12-25 23:15:28.757 [pool-2-thread-1] INFO [Task.java:15] pool-2-thread-1 is executing the task162017-12-25 23:15:28.757 [pool-2-thread-4] INFO [Task.java:15] pool-2-thread-4 is executing the task172017-12-25 23:15:28.757 [pool-2-thread-2] INFO [Task.java:15] pool-2-thread-2 is executing the task182017-12-25 23:15:28.758 [pool-2-thread-3] INFO [Task.java:15] pool-2-thread-3 is executing the task192017-12-25 23:15:28.758 [main] INFO [TaskExecutor.java:28] ==========End to execute the tasks==========
2,其它Java线程池
除了ThreadPoolExecutor,jdk还提供了其它多种线程池。通过Executors类的成员方法来生成实例。
1)newCachedThreadPool
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
2)newFixedThreadPool
public static ExecutorService newFixedThreadPool(intnThreads){return new ThreadPoolExecutor(nThreads,nThreads,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());}
3)newScheduledThreadPool,创建一个无尺寸上限的线程池,支持定时和周期性任务。
public static ScheduledExecutorService newScheduledThreadPool(intcorePoolSize){return new ScheduledThreadPoolExecutor(corePoolSize);}
4)newSingleThreadExecutor,只会使用唯一的线程来执行任务,保证所有的任务都按照指定顺序执行。
public static ExecutorService newSingleThreadExecutor(){return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1,1,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));}
二,spring线程池
ThreadPoolTaskExecutor是spring提供的线程池。其使用与Java线程池类似,不做赘述。直接查看示例代码。这里使用spring-boot的方式来进行配置。
任务类:
package com.wxy.popcorn.springthreadpool;import java.util.concurrent.CountDownLatch;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class SpringTask implements Runnable{ private Logger logger = LoggerFactory.getLogger(getClass()); private String tName; private CountDownLatch endGate; public SpringTask(String tName) { this.tName = tName; } public void run() { logger.info("{} is executing the {}", Thread.currentThread().getName(), tName); }}配置类
package com.wxy.popcorn.springthreadpool;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.PropertySource;import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;@Configuration@PropertySource("classpath:threadpool.properties")public class SpringConfig { @Bean @ConfigurationProperties(prefix = "thread.pool") public ThreadPoolTaskExecutor taskExecutor() { return new ThreadPoolTaskExecutor(); }}
属性文件
#线程池#线程池维护线程的最少数量thread.pool.core-pool-size=10#线程池维护线程的最大数量thread.pool.max-pool-size=20#缓存队列thread.pool.queue-capacity=100#允许的空闲时间thread.pool.keep-alive-seconds=300启动类
package com.wxy.popcorn.springthreadpool;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class SpringApp { public static void main(String[] args) { SpringApplication.run(SpringApp.class, args); }}测试类
package com.wxy.popcorn.springthreadpool;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import org.springframework.test.context.junit4.SpringRunner;@RunWith(SpringRunner.class)@SpringBootTestpublic class SpringTaskExecutorTest { @Autowired ThreadPoolTaskExecutor threadPoolTaskExecutor; @Test public void test() { for (int i=0; i< 20; i++) { threadPoolTaskExecutor.execute(new SpringTask("task"+i)); } }}测试结果
2017-12-25 23:08:59.215 [taskExecutor-2] INFO [SpringTask.java:18] taskExecutor-2 is executing the task12017-12-25 23:08:59.215 [taskExecutor-5] INFO [SpringTask.java:18] taskExecutor-5 is executing the task42017-12-25 23:08:59.215 [taskExecutor-9] INFO [SpringTask.java:18] taskExecutor-9 is executing the task82017-12-25 23:08:59.216 [taskExecutor-4] INFO [SpringTask.java:18] taskExecutor-4 is executing the task32017-12-25 23:08:59.216 [taskExecutor-3] INFO [SpringTask.java:18] taskExecutor-3 is executing the task22017-12-25 23:08:59.215 [taskExecutor-1] INFO [SpringTask.java:18] taskExecutor-1 is executing the task02017-12-25 23:08:59.215 [taskExecutor-7] INFO [SpringTask.java:18] taskExecutor-7 is executing the task62017-12-25 23:08:59.215 [taskExecutor-6] INFO [SpringTask.java:18] taskExecutor-6 is executing the task52017-12-25 23:08:59.215 [taskExecutor-8] INFO [SpringTask.java:18] taskExecutor-8 is executing the task72017-12-25 23:08:59.216 [taskExecutor-10] INFO [SpringTask.java:18] taskExecutor-10 is executing the task92017-12-25 23:08:59.224 [taskExecutor-2] INFO [SpringTask.java:18] taskExecutor-2 is executing the task102017-12-25 23:08:59.224 [taskExecutor-5] INFO [SpringTask.java:18] taskExecutor-5 is executing the task112017-12-25 23:08:59.224 [taskExecutor-9] INFO [SpringTask.java:18] taskExecutor-9 is executing the task122017-12-25 23:08:59.224 [taskExecutor-4] INFO [SpringTask.java:18] taskExecutor-4 is executing the task132017-12-25 23:08:59.224 [taskExecutor-3] INFO [SpringTask.java:18] taskExecutor-3 is executing the task142017-12-25 23:08:59.224 [taskExecutor-1] INFO [SpringTask.java:18] taskExecutor-1 is executing the task152017-12-25 23:08:59.225 [taskExecutor-7] INFO [SpringTask.java:18] taskExecutor-7 is executing the task162017-12-25 23:08:59.225 [taskExecutor-6] INFO [SpringTask.java:18] taskExecutor-6 is executing the task172017-12-25 23:08:59.225 [taskExecutor-8] INFO [SpringTask.java:18] taskExecutor-8 is executing the task182017-12-25 23:08:59.225 [taskExecutor-10] INFO [SpringTask.java:18] taskExecutor-10 is executing the task19