Java多线程的几种实现方式


前言

Executors和ThreadPoolExecutor和ThreadPoolTaskExecutor三种来讨论


一、Executors

1.Executors.newFixedThreadPool:创建一个固定大小的线程池,可控制并发的线程数,超出的线程会在队列中等待;
2.Executors.newCachedThreadPool:创建一个可缓存的线程池,若线程数超过处理所需,缓存一段时间后会回收,若线程数不够,则新建线程;
3.Executors.newSingleThreadExecutor:创建单个线程数的线程池,它可以保证先进先出的执行顺序;
4.Executors.newScheduledThreadPool:创建一个可以执行延迟任务的线程池;
5.Executors.newSingleThreadScheduledExecutor:创建一个单线程的可以执行延迟任务的线程池;
6.Executors.newWorkStealingPool:创建一个抢占式执行的线程池(任务执行顺序不确定)【JDK 1.8 添加】

重点

Executors不推荐使用:
根据阿里巴巴规范:创建的线程池需要自己把控,而Executors生成的线程池不够灵活,可能会造成资源浪费,或者请求堆积

二、ThreadPoolExecutor

手动创建的线程池
构造方法:

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {}

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {}

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {}

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {}

1.corePoolSize:核心线程数,长期存在的线程数
2.maximumPoolSize:最大线程数,最大存在的线程数
3.keepAliveTime:存活时长
4.unit:时长单位
5.threadFactory:⽤于生成线程,⼀般我们可以⽤默认的就可以了。
6.workQueue:任务队列,用于存储线程池的待执行任务的
7.handler:拒绝策略

拒绝策略

DiscardPolicy : 忽略旧任务(队列第一个任务)
AbortPolicy : 提示异常,拒绝执行(默认的拒绝策略)
CallerRunsPolicy : 使用调用线程池的线程来执行任务
DiscardOldestPolicy :  忽略最新任务 

ThreadPoolExecutor使用方式

1.定义一个线程池

/**
* 任务线程池
*/
final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 12, 30,TimeUnit.SECONDS, new ArrayBlockingQueue(200),
    (Runnable r, ThreadPoolExecutor executor)-> new ThreadPoolExecutor.AbortPolicy());
//定义了一个核心为2,最大长度为12,存活30秒,拒绝策略为抛异常的线程池

2.定义一个任务类

class AddTask implements Runnable{

     String targetId;
     String aiFunctionId;
     String labelId;
     String templateId;
     String catalogId;

     public AddTask(String targetId,String aiFunctionId,String labelId,String templateId,String catalogId){
         this.targetId=targetId;
         this.aiFunctionId=aiFunctionId;
         this.labelId=labelId;
         this.templateId=templateId;
         this.catalogId=catalogId;
     }

     @Override
     public void run() {
        buildTask(targetId,aiFunctionId,labelId,templateId,catalogId);
     }
 }
//buildTask是具体的实现方法

3.线程池执行

threadPool.execute(new AddTask(mediaId,aiFunctionId,labelId,templateId,catalogId));

三.ThreadPoolTaskExecutor

与上两种jdk提供的不同,这种是spring提供的线程池,是对第二种线程池的封装

1.定义线程池

没有提供带参构造方法,更适合配置@Async使用

@Configuration
public class ExecturConfig {
    @Bean("taskExector")
    public Executor taskExector() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        int i = Runtime.getRuntime().availableProcessors();//获取到服务器的cpu内核
        executor.setCorePoolSize(5);//核心池大小
        executor.setMaxPoolSize(100);//最大线程数
        executor.setQueueCapacity(1000);//队列程度
        executor.setKeepAliveSeconds(1000);//线程空闲时间
        executor.setThreadNamePrefix("tsak-asyn");//线程前缀名称
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());//配置拒绝策略
        return executor;
    }

使用注解异步方法

@Async("taskExector")
public void buildTask(String targetId,String aiFunctionId,String labelId,String templateId,String catalogId){
	
}

使用自带的方法,和ThreadPoolExecutor方法一样,需要定义个task实现Runnable

threadPoolTaskExecutor.execute(new Runnable);

注意

@Async可能出现失效的问题:
含有@Async或@Transational注解的bean被spring扫描时,spring会为其生成一个代理类,代理类继承原来的目标bean,如果该注解作用在方法上,则会重写目标bean对应方法,将该方法做相应的增强(如果该注解是作用在类上,则会增强该类的所有方法)。而方法a不含@Async或@Transational,所以不会增强处理,所以方法a是直接调用方法b,导致@Async或@Transational失效。

解决方法:
1.将带有注解的方法写在另外一个类中
2.使用反射获取代理类的方法:

A a = context.getBean(A.class); //从spring容器中重新获取A的代理对象,再调用b方法注解即生效
a.bMethod();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值