【深入浅出Java多线程】线程池

10, workQueue);

// 提交任务

pool.execute(()->{

System.out.println(“hello”);

});

常用线程池


ThreadPoolExecutor


在工程中,我们会使用Executors来快速new一个线程池,例如:

ExecutorService executorService = Executors.newFixedThreadPool(threadPoolNum, r -> new Thread(r, threadName));

Executors底层使用的是 ThreadPoolExecutor,我们可以通过ThreadPoolExecutor构造函数来了解ThreadPoolExecutor的一些行为。

ThreadPoolExecutor(

int corePoolSize,

int maximumPoolSize,

long keepAliveTime,

TimeUnit unit,

BlockingQueue workQueue,

ThreadFactory threadFactory,

RejectedExecutionHandler handler)

构造函数参数说明

corePoolSize:表示线程池保有的最小线程数。

maximumPoolSize:表示线程池创建的最大线程数。

keepAliveTime & unit:如果一个线程空闲了keepAliveTime & unit这么久,而且线程池的线程数大于 corePoolSize ,那么这个空闲的线程就要被回收了。

workQueue:工作队列,和上面示例代码的工作队列同义。

threadFactory:通过这个参数你可以自定义如何创建线程,例如你可以给线程指定一个有意义的名字。

handler:通过这个参数你可以自定义任务的拒绝策略。如果线程池中所有的线程都在忙碌,并且工作队列也满了(前提是工作队列是有界队列),那么此时提交任务,线程池就会拒绝接收。至于拒绝的策略,你可以通过 handler 这个参数来指定。ThreadPoolExecutor 已经提供了以下 4 种策略。

  • CallerRunsPolicy:提交任务的线程自己去执行该任务。

  • AbortPolicy:默认的拒绝策略,会 throws RejectedExecutionException。

  • DiscardPolicy:直接丢弃任务,没有任何异常抛出。

  • DiscardOldestPolicy:丢弃最老的任务,其实就是把最早进入工作队列的任务丢弃,然后把新任务加入到工作队列。

线程池默认工作行为

不会初始化 corePoolSize 个线程,有任务来了才创建工作线程;

当核心线程满了之后不会立即扩容线程池,而是把任务堆积到工作队列中;

当工作队列满了后扩容线程池,一直到线程个数达到 maximumPoolSize 为止;(如果线程池还没有扩容到最大线程数但是工作队列已经溢出,溢出的请求会被拒绝)

如果队列已满且达到了最大线程后还有任务进来,按照拒绝策略处理;

当线程数大于核心线程数时,线程等待 keepAliveTime 后还是没有任务需要处理的话,收缩线程到核心线程数。

ForkJoinPool


Fork/Join 是一个并行计算的框架,主要就是用来支持分治任务模型的,这个计算框架里的 Fork 对应的是分治任务模型里的任务分解,Join 对应的是结果合并。

Fork/Join 计算框架主要包含两部分,一部分是分治任务的线程池 ForkJoinPool,另一部分是分治任务 ForkJoinTask。这两部分的关系类似于 ThreadPoolExecutor 和 Runnable 的关系,都可以理解为提交任务到线程池,只不过分治任务有自己独特类型 ForkJoinTask。

ForkJoinPool 主要适用于计算密集型任务,Java中的parallelStream底层使用的就是ForkJoinPool。

下面是使用ForkJoinPool的一个简单例子:

public static void main(String[] args) {

ForkJoinPool forkJoinPool = new ForkJoinPool(4);

Fibonacci fibonacci = new Fibonacci(5);

Integer res = forkJoinPool.invoke(fibonacci);

System.out.println(res);

}

static class Fibonacci extends RecursiveTask{

final int n;

Fibonacci(int n){

this.n = n;

}

@Override

protected Integer compute() {

if(n<=1){

return n;

}

Fibonacci f1 = new Fibonacci(n-1);

f1.fork();

Fibonacci f2 = new Fibonacci(n-2);

return f2.compute() + f1.join();

}

}

FutureTask


我们可以通过FutureTask(Future接口的实现类)获取线程执行结果。FutureTask主要方法如下:

// 取消任务

boolean cancel(

boolean mayInterruptIfRunning);

// 判断任务是否已取消

boolean isCancelled();

// 判断任务是否已结束

boolean isDone();

// 获得任务执行结果

get();

// 获得任务执行结果,支持超时

get(long timeout, TimeUnit unit);

其中,两个 get() 方法都是阻塞式的,如果被调用的时候,任务还没有执行完,那么调用 get() 方法的线程会阻塞,直到任务执行完才会被唤醒。

ExecutorService executorService = Executors.newFixedThreadPool(10);

Future future = executorService.submit(() -> {

return 1 + 1;

});

Integer res = future.get();

System.out.println(res);

Integer res2 = future.get(1000, TimeUnit.SECONDS);

System.out.println(res2);

FutureTask 实现了 Runnable 和 Future 接口,由于实现了 Runnable 接口,所以可以将 FutureTask 对象作为任务提交给 ThreadPoolExecutor 去执行。

// 创建FutureTask

FutureTask futureTask

= new FutureTask<>(()-> 1+2);

// 创建线程池

ExecutorService es =

Executors.newCachedThreadPool();

// 提交FutureTask

es.submit(futureTask);

// 获取计算结果

Integer result = futureTask.get();

线程数量分析


多线程可以提高程序的响应速度和吞吐量,创建线程的数量会对实际效果产生非常大的影响,线程太少会浪费CPU的资源,线程太多则会导致线程的频繁切换,系统性能反而会下降。

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
中…(img-SRK8lEzt-1715163275503)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

  • 28
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值