多线程(线程池)-api-代码

1总概

1 频繁创建销毁都是资源的浪费,

 2创建线程的数量多少合适?少了会怎么样?

3 什么时候用?小任务使用(单个任务时间短)

4 线程池不要混用,什么任务都用一个线程池,不要随便用

5 使用时要打印线程日志

2 参数的含义

当线程池中corePoolSize使用完毕之后,多出来的任务就会进入缓存队列;

当缓存队列也存放满了之后,还有大量的任务,这时将会创建线程池中支持的最大量的线程,然后执行缓存队列里面的任务,而外面的任务进入缓存队列中;当线程池中的线程达到最大时,缓存队列也存满之后,这时该线程池将会执行拒绝策略。
 

3线程的策略

默认策略:当任务添加到线程池中被拒绝时,它将抛出 RejectedExecutionException 异常。(该策略下,直接丢弃任务,并抛出RejectedExecutionException异常)
new ThreadPoolExecutor.AbortPolicy();

任务将由调用者线程去执行
CallerRunsPolicy

当任务添加到线程池中被拒绝时,默认情况下它将丢弃被拒绝的任务。(即该策略下,直接丢弃任务,什么都不做)
DiscardPolicy
(该策略下,抛弃进入队列最早的那个任务,然后尝试把这次拒绝的任务放入队列)
DiscardOldestPolicy

实现RejectedExecutionHandler接口,可自定义处理器

4 api应用

1:submit() 这个方法特别,如果任务出现异常异常信息只能通过 .get()方法获取到,才能终止程序

//执行无返回值任务 有异常会抛出异常,终止程序
pool.execute(()->{
    int a=5/0;
    System.out.println(Thread.currentThread().getName());
});
//执行有返回值任务 有异常不会抛出异常,不会终止程序,而是在submit.get()才会返回异常信息,并终止程序

 Future<Order> submit = pool.submit(() -> {
     int a=5/0;
    Order order = new Order();
    return order;
});
//如果出现异常,只能通过get()方法获取异常,并终止程序。
submit.get();
// 阻塞全部任务直到全部执行完所有任务这个是简单写法, 其他方式为必须实现接口 Callable
// 如果返回值是统一类型没有问题,但是没有统一类型如何优雅获取返回值在操作数据呢?
List<Future<Object>> aa = pool.invokeAll(Arrays.asList(() -> {
    System.out.println("aa");
    return "1";
}, () -> {
    return 1;
}));
for (Future<Object> objectFuture : aa) {
    Object o = objectFuture.get();
}

5延时任务

5.1 timer

  1. 延迟任务都是由一个线程完成,所有程序都是串行执行。会导致整个程序都慢,
  2. 第一个任务异常也会导致程序终止

ScheduledExecutorService特点:

  1 :当线程池只有一个线程的时候,大家会共用这一个线程,第一个任务做完,放回线程池 中,第二个任务取出继续执行,也就是说,线程不够,会有延时

2:每个任务都是独立的了,异常不会影响其他任务执行

3:下图只是举例:不要那么创建线程池。

//每隔一段时间执行一次任务 
scheduled.scheduleAtFixedRate(()->{
            log.info("定时执行任务");
        },1,2,TimeUnit.SECONDS);// 初始的延迟 1秒,每隔2秒执行一次

     延时执行任务
  scheduled.schedule(() -> {
            log.info("schedule2");
        }, 1, TimeUnit.SECONDS);

forkjoin

forkjoin: 特点就是任务拆分,将一个大的任务拆分成小的任务,在合并

场景应用:个人觉得比较少,比如查询大量数据,又根据某个规则处理,

   本人做过一个需求 excel大量数据插入不同的店铺,觉得可以用这个思想,一个店铺一个任务去处理即可。

       1 数据量大处理时间长  2 数据可以按照某个规则统一处理

RecursiveAction:用于没有返回结果的任务
RecursiveTask: 用于有返回结果的任务

   @Autowired
    TUserDao userDao;
    @Test
    void Thread1() {
        ForkJoinPool forkJoinPool = new ForkJoinPool(5);
        int total=100;//查询总共100条数据
        forkjoinDemo forkjoinDemo = new forkjoinDemo(false,total,userDao);
        List<t_user> invoke = forkJoinPool.invoke(forkjoinDemo);
        System.out.println(invoke);

    }
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.RecursiveTask;

public class forkjoinDemo extends RecursiveTask<List<t_user>> {
    TUserDao userDao ;
    int total=100;
     boolean flag=false;//是否执行
    public forkjoinDemo(boolean flag,int total, TUserDao userDao) {
        this.flag=flag;
        this.total=total;
        this.userDao=userDao;
    }
    @Override
    protected List<t_user> compute() {
        if(flag){
            //执行方法
            return userDao.queryUser();
        }
          //方式一 有指定批次的时候
        forkjoinDemo forkjoinOne1 = new forkjoinDemo(true,50, userDao);
        forkjoinDemo forkjoinOne2 = new forkjoinDemo(true,100, userDao);
        // 子任务执行(fork)
        invokeAll(forkjoinOne1,forkjoinOne2);
        // 任务汇总
        List<t_user> userList1 = forkjoinOne1.join();
        List<t_user> userList2 = forkjoinOne2.join();
        userList1.addAll(userList2);
        return userList1;
        //方式二
            //将任务分成几个批次
            int bath=100/50;
        List<t_user> all = new ArrayList<>();
            for (int i = 0; i < bath; i++) {
                forkjoinDemo forkjoinDemo = new forkjoinDemo(true,50, userDao);
                invokeAll(forkjoinDemo);
                List<t_user> join = forkjoinDemo.join();
                all.addAll(join);
            }
        return all;
    }
}

6个人常用的1.8CompletableFuture

1:他只有异步方法:带返回值和不带返回值, 带线程池和不带线程池

    自己创建线程池,不许使用他的不带线程池。

  2:所有方法不会抛异常,只有调用 get().才会抛出异常

public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
        return asyncSupplyStage(asyncPool, supplier);
    }
 
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,Executor executor) {
    return asyncSupplyStage(screenExecutor(executor), supplier);
}
 
public static CompletableFuture<Void> runAsync(Runnable runnable) {
    return asyncRunStage(asyncPool, runnable);
}
 
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor) {
    return asyncRunStage(screenExecutor(executor), runnable);
}

总结api功能:

总结下面的api: 后缀带Async都是线程池出一个线程执行。不带Async的都是由main方法自己去调用的

thenApplyAsync/thenApply  (能接收结果,能返回结果)

相同点:1 承接过来上一个任务的结果,并作处理。2 并且处理完可以返回处理结果

不同点: thenApplyAsync 由线程池在出一个线程执行

               thenApply由主方法执行

 thenAccept和thenAcceptAsync (能接收结果,无返回)

相同点:1 承接过来上一个任务的结果,并作处理。无返回。

不同点: thenAcceptAsync 由线程池在出一个线程执行

               thenAccept由主方法执行

thenRun/ thenRunAsync (无接收,无返回)

相同点:类似于回调函数,

不同点: thenRunAsync 由线程池在出一个线程执行

               thenRun由主方法执行

whenComplete/whenCompleteAsync (能接收结果和异常信息,无返回)

相同点:1 承接过来上一个任务的结果,并作处理。无返回。

               上一个任务无异常,e为null ,有异常 接收结果为null  e是上一个任务的异常信息

不同点: thenRunAsync 由线程池在出一个线程执行

               thenRun由主方法执行

 @Resource(name = "queryThreadPoolExecutor")
    private ThreadPoolExecutor queryThreadPoolExecutor;

    @Test
    void contextLoads() throws ExecutionException, InterruptedException {
        //无返回值应用 例如插入日志
   /*      CompletableFuture.runAsync(() -> {
              userDao.insertSelective(new t_user());
         }, queryThreadPoolExecutor);*/
        //异步执行并且有返回值
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("supplyAsync==" + Thread.currentThread().getName());
            //supplyAsync== pool-2-thread-1
            // int a =10/0;
            //不会抛异常,只有 future1.get();才会抛出异常
            return "future1";
        }, queryThreadPoolExecutor);

        // thenApplyAsync/thenApply 承接过来上一个任务的结果,并作处理,不
        // 同之处在于 thenApplyAsync 由线程池在出一个线程执行
        // thenApply由主方法执行
        // future1 的返回值承接过来(result)  执行是由线程池中出的一个线程
        CompletableFuture<String> stringCompletableFuture = future1.thenApplyAsync(result -> {
            System.out.println("thenApplyAsync==" + Thread.currentThread().getName() + "结果:" + result);
            //thenApplyAsync== pool-2-thread-2 结果:future1
            // future1抛异常了 将不会执行这个方法了
            return "thenApplyAsync";
        }, queryThreadPoolExecutor);
        //future1 的返回值承接过来(result)  执行是由main线程执行了
        CompletableFuture<String> stringCompletableFuture1 = future1.thenApply((result) -> {
            System.out.println("thenApply==" + Thread.currentThread().getName() + "结果:" + result);
            //thenApply== main 结果:future1
            // future1抛异常了 将不会执行这个方法了
            return "thenApply";
        });

        // thenAccept和thenAcceptAsync  都是承接过来上一个任务的结果,并作处理,但是处理完都是无返回值
        // thenAccept由主方法执行,thenAcceptAsync由线程池再出一个线程执行
        future1.thenAccept((result) -> {
            System.out.println("thenAccept==" + Thread.currentThread().getName() + "结果:" + result);
            // thenAccept== main 结果:future1
            // future1抛异常了 将不会执行这个方法了
        });
        future1.thenAcceptAsync((result) -> {
            System.out.println("thenAcceptAsync==" + Thread.currentThread().getName() + "结果:" + result);
            // thenAcceptAsync==ForkJoinPool.commonPool-worker-9结果:future1 用它的线程池时的打印
            // thenAcceptAsync==pool-2-thread-3 结果:future1  我自己的线程池打印
            // future1抛异常了 将不会执行这个方法了
        }, queryThreadPoolExecutor);


        // thenRun和 thenRunAsync   类似于回调函数, 无入参无返回值
        // thenRun 由主方法执行, thenRunAsync 由线程池再出一个线程执行
        future1.thenRun(() -> {
            System.out.println("thenRun==" + Thread.currentThread().getName());
            // thenRun==main
        });
        future1.thenRunAsync(() -> {
            System.out.println("thenRunAsync==" + Thread.currentThread().getName());
            // thenRunAsync==pool-2-thread-4
        }, queryThreadPoolExecutor);

        //whenComplete和whenCompleteAsync 都是承接过来上一个任务的结果,和异常 并作处理,但是处理完都是无返回值
        // 无异常时 e为null, 有异常时  result 为null 但是不调用get()不会抛出异常
        CompletableFuture<String> stringCompletableFuture2 = future1.whenComplete((result, e) -> {
            System.out.println("thenRun==" + Thread.currentThread().getName() + " result:" + result + " e:" + e);
            // thenRun==main  result:future1 e:null
            // thenRun==main result:null e:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero

        });
        CompletableFuture<String> stringCompletableFuture3 = future1.whenCompleteAsync((result, e) -> {
            System.out.println("thenRun==" + Thread.currentThread().getName() + " result:" + result + " e:" + e);
            // thenRun==pool-2-thread-5  result:future1 e:null
            // thenRun==pool-2-thread-5 result:null e:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
        }, queryThreadPoolExecutor);


        // stringCompletableFuture2.get();

        //  future1.get();
    }

写来写去发现这个文章写的很好,挺全面的。

CompletableFuture使用详解(全网看这一篇就行)_代码搬运工阿新的博客-CSDN博客_completablefuture 详解

细数线程池五大坑,一不小心线上就崩了_普通网友的博客-CSDN博客_线程池使用注意坑

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值