前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java并发编程——四种线程池的使用及分析

Java并发编程——四种线程池的使用及分析

作者头像
向着百万年薪努力的小赵
发布2022-12-02 09:37:49
3560
发布2022-12-02 09:37:49
举报
文章被收录于专栏:小赵的Java学习

执行一个异步任务你还只是new Thread吗? 那你就out太多了,new Thread的弊端如下:

a. 每次new Thread新建对象性能差。

b. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom。

c.缺乏更多功能,如定时执行、定期执行、线程中断。

用线程池吧,少年

相比new Thread,Java提供的四种线程池的好处

a. 重用存在的线程,减少对象创建、消亡的开销,性能佳。

b. 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。

c. 提供定时执行、定期执行、单线程、并发数控制等功能。

Java提供的四种线程池

  1. newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
  2. newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
  3. newCachedThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
  4. newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。

了解之后,就让我们来使用一下 代码示例:

1.newFixedThreadPool

创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

代码语言:javascript
复制
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
final int index = i;
fixedThreadPool.execute(new Runnable() {

@Override
public void run() {
try {
System.out.println(index);
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}

因为线程池大小为3,每个任务输出index后sleep 2秒,所以每两秒打印3个数字。 定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors()。可参考PreloadDataCache。

2.newSingleThreadExecutor

创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

代码语言:javascript
复制
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int index = i;
singleThreadExecutor.execute(new Runnable() {

@Override
public void run() {
try {
System.out.println(index);
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}

结果依次输出,相当于顺序执行各个任务。

3.newCachedThreadPool

创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

代码语言:javascript
复制
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
final int index = i;
try {
Thread.sleep(index * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}

cachedThreadPool.execute(new Runnable() {

@Override
public void run() {
System.out.println(index);
}
});
}

线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。

4.newScheduledThreadPool

创建一个定长线程池,支持定时及周期性任务执行。 延迟执行示例代码如下:

代码语言:javascript
复制
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.schedule(new Runnable() {

@Override
public void run() {
System.out.println("delay 3 seconds");
}
}, 3, TimeUnit.SECONDS);

表示延迟3秒执行。

定期执行示例代码如下:

代码语言:javascript
复制
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {

@Override
public void run() {
System.out.println("delay 1 seconds, and excute every 3 seconds");
}
}, 1, 3, TimeUnit.SECONDS);

表示延迟1秒后每3秒执行一次。

分析

那光会使用怎么能行,我们还要进去看看它的原理: 点进去创建固定线程池的方法,

在这里插入图片描述
在这里插入图片描述

原来是调了一个方法,把线程数量当参数传了进去 换一个看看,再点进去缓存线程池

在这里插入图片描述
在这里插入图片描述

又调用了这个方法,看来ThreadPoolExecutor()这个方法才是创建线程池的真正的方法,让我们再点进去这个方法 打开Structure,看到这个方法有四个重载,传递的不同参数

在这里插入图片描述
在这里插入图片描述

这里给出参数是什么意思,供大家参考

代码语言:javascript
复制
public ThreadPoo1Executor(
int corePool size,//核心线程数量
int maximumPoolsize,/最大线程数
long keepAliveTime,//超时时间,超出核心线程数量以外的线程空余存活时间
Timeunit unit,//存活时间单位
BlockingQueue<Runnable> workQueue,//保存执行任务的队列
ThreadFactory threadFactory,//创建新线程使用的工厂
RejectedExecutionHandler handler//当任务无法执行的时候的处理方式
)

这里大家注意一下这两个参数

代码语言:javascript
复制
int corePool size,//核心线程数量
int maximumPoolsize,/最大线程数

其实这就是有编制的和临时工的区别,什么意思呢 就是如果我们公司某个项目赶得紧,人手不够了,怎么办?扩招吗,可是平时又用不到这么多人,那我们可以找外包公司招点外包人员嘛,临时借过来等项目完成了再还回去。 即核心到最大 之间的这部分,是可变的,需要就有,不需要就没有。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-09-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Java提供的四种线程池
    • 1.newFixedThreadPool
      • 2.newSingleThreadExecutor
        • 3.newCachedThreadPool
          • 4.newScheduledThreadPool
      • 分析
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档