【Java 并发编程】ThreadPoolExecutor简单应用

(1024程序员节快乐,并发编程学习内容来源于douyin cat老师)

什么是线程池

白话一点理解就是一个池子,里面存放着已经创建好的线程,当有任务提交到线程池里面来的 时候,池子中的某个线程就会主动去执行该任务,当提交过来的任务比较多,池子中的线程数 不够用时,需要能自动扩充新的线程到池子中,当然也不能无限地扩充线程数量,能进行统一 的配置,能配置最大线程个数,而当任务比较少时,池子中的线程个数就自动回收,把线程资 源释放掉;并且通常情况下,为了能缓存提交过来的未被处理的任务,就需要有一个任务队列 来存放,这就是一个线程池,你甚至可以自己来实现一个线程池;

为什么要有线程池

我们知道创建和销毁一个对象是很费时间的,特别是一些比较耗费资源的对象的创建和销毁, 比如创建数据库连接,创建网络连接,创建线程等,所以就出现“池化技术”,即复用已经创 建的对象,那么这样做能够带来 3 个好处:

  • 降低资源消耗,通过复用已经创建的线程降低线程创建和销毁造成的系统资源消耗;

  • 提高性能,当执行大量异步任务时线程池能够提供更好的性能,在不使用线程池时,每 当需要执行异步任务时直接 new 一个线程来运行,而线程的创建和销毁是需要开销的,而线 程池里面的线程是可复用的,不需要每次执行异步任务时都重新创建和销毁线程,直接执行任 务即可;

  • 方便线程管理,线程是不能随随便滥用的,当不停地创建线程可能导致系统资源消耗殆 尽而崩溃,使用线程池可以限制创建的线程个数、动态新增线程数量等,提高了线程的可管理 性;

线程池的使用案例代码

线程池配置类

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 线程池配置
 * 根据业务不同(有的业务执行快,有的业务执行慢),使用不同的线程池
 * 自定义线程工厂
 * 自定义拒绝策略,暂时用"调用者运行策略"
 */
@Configuration
public class ThreadPoolConfig {

    /**
     * 核心线程数
     */
    private static final int corePoolSize = 8;

    /**
     * 线程池中允许的最大线程数
     */
    private static final int maximumPoolSize = 16;

    /**
     * 线程空闲超时时间(秒)
     */
    private static final long keepAliveTime = 30;

    /**
     * 任务队列
     */
    private static final int capacity = 100;

    /**
     * 站内信、短信-线程池
     *
     * @return
     */
    @Bean(name = "msgThreadPoolExecutor")
    public ThreadPoolExecutor msgThreadPoolExecutor() {
        return new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(capacity),
                new CustomThreadFactory("msg"),
                new ThreadPoolExecutor.CallerRunsPolicy());
    }
}

自定义线程池工厂

import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 自定义线程工厂
 */
public class CustomThreadFactory implements ThreadFactory {

    private static final AtomicInteger poolNumber = new AtomicInteger(1);
    private final ThreadGroup group;
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    private final String namePrefix;

    CustomThreadFactory(String functionFlag) {
        SecurityManager s = System.getSecurityManager();
        group = (s != null) ? s.getThreadGroup() :
                Thread.currentThread().getThreadGroup();
        //log4j日志输出的线程名称没有变
        namePrefix = functionFlag + "-pool-" +
                poolNumber.getAndIncrement() +
                "-thread-";
    }

    @Override
    public Thread newThread(Runnable r) {
        Thread t = new Thread(group, r,
                namePrefix + threadNumber.getAndIncrement(),
                0);
        if (t.isDaemon()) {
            t.setDaemon(false);
        }
        if (t.getPriority() != Thread.NORM_PRIORITY) {
            t.setPriority(Thread.NORM_PRIORITY);
        }
        return t;
    }
}

线程调用执行

这两行代码用于子线程获取父线程的headers信息,比如access_token,用于openfeign调用。

RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
RequestContextHolder.setRequestAttributes(requestAttributes);

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.annotation.Resource;
import java.text.MessageFormat;
import java.util.Date;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 站内信发送工具类
 */
@Service
public class MsgZnxUtil {

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


    @Resource
    private ThreadPoolExecutor msgThreadPoolExecutor;

    /**
     * 发送站内信
     *
     * @param action
     */
    public void sendZnx(String action) {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        try {
            msgThreadPoolExecutor.execute(() -> {
                RequestContextHolder.setRequestAttributes(requestAttributes);
              
                //code
            });
        } catch (Exception e) {
            logger.error(String.format("%s,站内信发送失败", action), e);
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
>