【工具类】实现自定义线程池

 概要:

1.基于spring-context实现
2.基于JDK1.8实现

 

方案一.使用org.springframework:spring-context:5.1.2.RELEASE:定义线程池

第一步,先在配置类中定义一个线程池,比如:

package com.songzhen.howcool.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 自定义线程池配置类
 *
 * @author Lucas
 * @version 1.0
 * @date 2018/10/15 17:51
 **/
@EnableAsync
@Configuration
public class TaskPoolConfig {

    @Bean("taskExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(32);
        executor.setQueueCapacity(200);
        executor.setKeepAliveSeconds(60);
        executor.setThreadNamePrefix("taskExecutor-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }
}
View Code

上面我们通过使用ThreadPoolTaskExecutor创建了一个线程池,同时设置了以下这些参数:

  • 核心线程数10:线程池创建时候初始化的线程数
  • 最大线程数32:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
  • 缓冲队列200:用来缓冲执行任务的队列
  • 允许线程的空闲时间60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
  • 线程池名的前缀taskExecutor-:设置好了之后可以方便我们定位处理任务所在的线程池
  • 线程池对拒绝任务的处理策略:这里采用了CallerRunsPolicy策略,当线程池没有处理能力的时候,该策略会直接在 execute 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务

使用线程池

第二步,在定义了线程池之后,我们如何让异步调用的执行任务使用这个线程池中的资源来运行呢?方法非常简单,我们只需要在@Async注解中指定线程池名即可,比如:

package  com.songzhen.howcool.biz;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

/**
 * 异步调用自定义线程池处理任务
 *
 * @author Lucas
 * @version 1.0
 * @date 2018/10/15 17:51
 **/
@Component
public class Task {

    private static final Logger logger = LoggerFactory.getLogger(Task.class);

    @Async("taskExecutor")
    public void doTask() {
        logger.info("开始做任务");
        long start = System.currentTimeMillis();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            logger.error("Have a interruptedException {}", e);
            Thread.currentThread().interrupt();
        }

        long end = System.currentTimeMillis();
        logger.info("完成任务,耗时:{} 毫秒", end - start);
    }
}
View Code

 


 

方案二.使用JDK本身java.util.concurrent包里自带Util:定义线程池

private static final ThreadFactory THREAD_FACTORY = new ThreadFactoryBuilder().setNameFormat("taskExecutor-pool-%d").build();

private static final ExecutorService EXECUTOR = new ThreadPoolExecutor(1, 3, 120, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1024), THREAD_FACTORY, new ThreadPoolExecutor.AbortPolicy());

/**
     * 处理业务
     *
     * @date 16:10 2019/4/10
     */
public void handlerBusiness {
        EXECUTOR .execute(()-> sendMessage(mobile, context));
        EXECUTOR .shutdown(); …
    }

/**
     * 发送短信
     *
     * @date 16:11 2019/4/10
     */
public void sendMessage(String mobile, String context) {
        System.out.println(Thread.currentThread().getName()));
        int remainingTimes = 3;
        try {

            do {
                // TODO调用短信平台发送短信

                remainingTimes--;

                Thread.sleep(20000);

            } while (remainingTimes <= 3);

        } catch (InterruptedException e) {
            System.out.println("Thread have a interruptedException");
            // 只对阻塞线程起作用,当线程阻塞时退出线程,对于正在运行的线程,没有任何作用!
            Thread.currentThread().interrupt();
        }
    }
View Code
private void getAddress() throws Exception {
        // 创建线程池
        ExecutorService pool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 16 + 2);
        BlockingQueue<Future<String>> queue = new LinkedBlockingQueue<>();

        // 扔任务
        for (int i = 0; i < 10; i++) {
            Future<String> future = pool.submit(new TaskGMapThread(0, 0));
            queue.add(future);
        }

        // 检查线程池任务执行结果
        for (int i = 0; i < 10; i++) {
            String address = queue.take().get();
        }

        // 关闭线程池
        pool.shutdown();
    }

    class TaskGMapThread implements Callable<String> {

        private double latitude;
        private double longitude;

        public TaskGMapThread(double latitude, double longitude) {
            this.latitude = latitude;
            this.longitude = longitude;
        }

        @Override
        public String call() throws Exception {

            return "key"+latitude+latitude;

        }
    }
View Code

  

posted @ 2018-12-03 18:06  青取之于蓝  阅读(772)  评论(0)    收藏  举报