基于线程池实现多线程任务

来源:互联网 发布: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



阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 梦到雪 做梦梦到雪是什么意思 梦到雪是什么意思 梦见下好大的雪 梦见好多雪 梦见厚厚的雪 孕妇梦见满地都是雪 梦见满地雪 梦见雪很厚 梦见铲雪 梦见吃雪是什么意思 孕妇梦见地上很厚的雪 梦见很厚的雪预示什么 雪代表的寓意 梦见玩雪 做梦梦到雪 做梦梦见雪 做梦下雪是什么兆头 做梦梦到下雪是什么征兆 梦到下雪好不好 梦见风 梦见风很大 梦见好大的风 梦见很大的风 梦见很大的风吹进家里 梦见风大雨大是什么兆头 梦见风特别大吹进屋子 梦见起风 梦到风 梦见香 梦见香断了 梦见点香 梦见自己吃饭吃的很香 梦见上香是什么意思 梦见买香 女人梦见吃饼还很香 梦见吃东西很香 梦见烧香香断了 梦见香瓜是什么意思 梦见一匹白马 梦见黑马是什么意思