java线程池一创建就立马有线程了么,java线程池

线程池是一种池技术,就像连接池一样。线程池本身也是一个对象,这个对象可以管理自己池子中的众多线程,以使他们被高效率的反复利用

为何要使用线程池

降低资源消耗,防止资源不足。

线程也是对象,频繁的创建线程对象,就会频繁的去触发内存分配和内存占用,大量消耗性能,内存占用过多可能会导致内存溢出。

频繁的创建和销毁线程对象即频繁的消耗cpu,影响服务器性能。

因为有大量的对象产生,就会有大量的GC回收,大量的gc可能会导致gc抖动,卡顿等现象,也会影响服务器性能。

提高响应速度

当需要被线程执行的任务到达时,因线程池中已有创建好的线程,所以可以直接用创建好的线程去执行任务,而无需先创建一个线程,然后在执行任务,节省了程序运行时间。

提高线程的可管理性

可以控制线程的数量和并法数,也可以防止无限制的创建线程数量导致性能和内存溢出等问题。

提供更强大的功能,延时定时线程池

比如,我们需要一个任务每一秒钟执行一次。

java线程池种类

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

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

newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。

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

不过在工作中,如果你使用Executors的方式去创建线程,可能会失业的,原因直接贴上阿里开发手册的说明。

74686327c8d5

image.png

正确创建线程池的姿势

74686327c8d5

image.png

线程池创建线程执行和拒绝策略如下:

当一个任务通过 execute(Runnable) 方法欲添加到线程池时,线程池采用的策略如下(即添加任务的策略):

如果此时线程池中的数量小于 corePoolSize ,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。

如果此时线程池中的数量等于 corePoolSize ,但是缓冲队列 workQueue 未满,那么任务被放入缓冲队列。

如果此时线程池中的数量大于 corePoolSize ,缓冲队列 workQueue 满,并且线程池中的数量小于maximumPoolSize ,建新的线程来处理被添加的任务。

如果此时线程池中的数量大于 corePoolSize ,缓冲队列 workQueue 满,并且线程池中的数量等于maximumPoolSize ,那么通过 handler 所指定的策略来处理此任务。

使用有界队列时,如果任务队列满了则执行拒绝策略(第二个用的多些)

ThreadPoolExecutor.AbortPolicy 丢弃任务,并抛出 RejectedExecutionException 异常。备注:此种方法必须要捕获线程池添加任务代码,不然添加异常就不会走shutdown关闭线程池代码,会导致线程池一直处于未关闭状态。

ThreadPoolExecutor.CallerRunsPolicy:该任务被线程池拒绝,由调用 execute方法的线程执行该任务。备注:其实就是主线程去执行被线程池拒绝的任务。

ThreadPoolExecutor.DiscardOldestPolicy : 抛弃队列最前面的任务,然后重新尝试执行任务。备注:就是移除队列中第一个添加进去的任务,把后来的任务加在队列最后。

ThreadPoolExecutor.DiscardPolicy,丢弃任务,不过也不抛出异常。备注:直接丢弃队列满了之后添加进来的任务。

如何优雅的关闭线程池:

线程池有2种关闭方法:

shutdown():线程池拒接收新提交的任务,同时等待线程池里的任务执行完毕后关闭线程池。

shutdownNow() :线程池拒接收新提交的任务,同时立马关闭线程池,线程池里的任务不再执行,并能获取未被执行的任务。

关闭线程池的时候,线程池中的线程有4种状态:

处于空闲状态 — shutdown: 正常退出,shutdownNow: 正常退出

处于正在处理任务的状态 — shutdown: 任务处理完成正常退出,shutdownNow: 任务处理完成正常退出

处于正在从任务队列读取任务的状态— shutdown: 继续读取并任务执行,直到所有任务全部执行完毕退出,shutdownNow: 停止读取并退出

处于阻塞状态— shutdown: 线程继续阻塞,并等待阻塞结束继续执行任务,shutdownNow: 抛出InterruptedException异常

所以,我们该如何正确关闭线程池

当调用shutdownNow()方法时,如果确定可能会有阻塞的任务存在,一定要捕获异常进行处理

当调用shutdown()方法时,一定要确保任务里不会有永久阻塞等待的线程,否则线程池就关闭不了,不行的话可以等待一段时间后调用shutdownNow()方法

如果要在线程池任务执行完关闭之后才能执行其他的主逻辑,那么我们就必须要等到线程池任务全部执行结束,需要注意的是,不管是shutdown还是shutdownNow方法,其实都是发起线程关闭,但是线程池此时并不一定完全关闭了,因为可能有线程还在执行任务或者队列里还有任务等待执行,所以我们需要通过pool.awaitTermination(2, TimeUnit.SECONDS)方法去判断线程池是否真的完全关闭了

pool.awaitTermination(2, TimeUnit.SECONDS)

第一个参数为时间,第二个参数为单位

这是一个阻塞方法,返回true和false,线程池关闭为true,未关闭为false

在指定时间内,如果线程池关闭了,此方法结束阻塞,返回true,继续执行之后的代码

在指定时间内,如果线程池未关闭,会一直阻塞,直到指定时间到了返回false。

所以,一般shutdown()或者shutdownNow()方法要配合awaitTermination()方法一起使用。

其实关键就在于是否有阻塞的任务,下面是一种参考处理方法

threadPool.shutdown(); // Disable new tasks from being submitted

// 设定最大重试次数

try {

// 等待 60 s

if (!threadPool.awaitTermination(60, TimeUnit.SECONDS)) {

// 调用 shutdownNow 取消正在执行的任务

threadPool.shutdownNow();

// 再次等待 60 s,如果还未结束,可以再次尝试,或者直接放弃

if (!threadPool.awaitTermination(60, TimeUnit.SECONDS))

System.err.println("线程池任务未正常执行结束");

}

} catch (InterruptedException ie) {

// 重新调用 shutdownNow

threadPool.shutdownNow();

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值