JAVA并发编程—线程池的使用

目录

一、线程池

1、为什么使用线程池

2、线程池概念

3、线程池初始化及线程池的状态

4、线程池核心类ThreadPoolExecutor

5、四种常见的线程池实现方式


一、线程池

1、为什么使用线程池

       使用多线程,可以帮助我们很好的解决一些并发环境下的问题,提升程序运行速度。

       但如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,占用大量系统资源,可能会造成系统奔溃。那么有没有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务?

        线程池出现了。

2、线程池概念

       在系统启动时即创建大量空闲的线程,这些线程的集合称为线程池。程序将一个任务传给线程池,线程池拿到任务后,就查询是否有空闲的线程,如果有,线程池就会启动一条线程来执行这个任务,执行结束以后,该线程并不会死亡,而是再次返回线程池中成为空闲状态,等待执行下一个任务。

       一个线程只能执行一个任务,但是一个线程池可以处理多个任务请求。

3、线程池初始化及线程池的状态

   默认情况下,创建线程池之后,线程池中是没有线程的,需要提交任务之后才会创建线程。

   在实际中如果需要线程池创建之后立即创建线程,可以通过以下两个方法办到:

  • prestartCoreThread():初始化一个核心线程;
  • prestartAllCoreThreads():初始化所有核心线程

  下面是这2个方法的实现:

public boolean prestartCoreThread() {
    return addIfUnderCorePoolSize(null); //注意传进去的参数是null
}
 
public int prestartAllCoreThreads() {
    int n = 0;
    while (addIfUnderCorePoolSize(null))//注意传进去的参数是null
        ++n;
    return n;
}

在ThreadPoolExecutor中定义了一个volatile变量,另外定义了几个static final变量表示线程池的各个状态:

volatile int runState; //当前线程池的状态,volatile变量用来保证线程之间的可见性
static final int RUNNING    = 0; //初始
static final int SHUTDOWN   = 1; //此时线程池不能够接受新的任务,它会等待所有任务执行完毕
static final int STOP       = 2; //此时线程池不能接受新的任务,并且会去尝试终止正在执行的任务
static final int TERMINATED = 3;//当线程池处于SHUTDOWN或STOP状态,并且所有工作线程已经销毁,任务缓存队列已经清空或执行结束后,线程池被设置为TERMINATED状态

调用了shutdown()方法,则线程池处于SHUTDOWN状态;

调用了shutdownNow()方法,则线程池处于STOP状态;

4、线程池核心类ThreadPoolExecutor

         以下是ThreadPoolExecutor类的四个构造方法:

public class ThreadPoolExecutor extends AbstractExecutorService {

    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue);
 
    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,RejectedExecutionHandler handler);
 
    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler);
}

       下面解释下一下构造器中各个参数的含义: 

        corePoolSize :核心线程数,默认情况下,线程池中并没有任何线程,而是等待有任务到来才创建线程去执行任务,除非调用了prestartAllCoreThreads()或者prestartCoreThread()方法,即在没有任务到来之前就创建corePoolSize个线程或者一个线程。默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;

        maximumPoolSize : 最大线程数

        keepAliveTime :当线程数大于核心线程时,此为终止前多余的空闲线程等待新任务的最长时间

        unit :时间单位,有7种取值,在TimeUnit类中有7种静态属性

        workQueue :一个阻塞队列,用来存储等待执行的任务,一般workQueue有以下几种方式

            队列

                                                       解释

线程安全

ArrayBlockingQueue

基于数组的先进先出,创建时必须指定大小,超出核心线程数corePoolSize的任务,则加入到该队列中,只能加该队列设置的大小,其余的任务则创建新线程,直到(corePoolSize+新建线程)> maximumPoolSize

线程安全

LinkedBlockingQueue

基于链表的先进先出,无界队列,所以maximumPoolSize不起作用。超出核心线程数corePoolSize的任务,则加入到该队列中,直到资源耗尽

线程安全

SynchrousQueue

不会保存提交任务,直接提交,超出核心线程数corePoolSize的任务,直接创建新的线程来执行任务,直到(corePoolSize+新建线程)> maximumPoolSize。

线程安全

        threadFactory : 创建线程的工厂

        handler :由于超出线程范围和队列容量而使执行被阻塞时所使用的处理程序,有以下四种取值:

ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。 
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。 
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务

5、四种常见的线程池实现方式

       以下四种方法,都是Executors提供的静态方法,一般情况下,如果这几种方法可以满足您的需求,就尽量使用它提供的方法,因为自己去手动配置ThreadPoolExecutor的参数有点麻烦,要根据实际任务的类型和数量来进行配置。

      线程池的返回值ExecutorService是Java提供的用于管理线程池的类。该类的两个作用:控制线程数量和重用线程

    (1)Executors.newCacheThreadPool():可缓存线程池,先查看池中有没有以前建立的线程,如果有,就直接使用。如果没有,就建一个新的线程加入池中,缓存型池子通常用于执行一些生存期很短的异步型任务。

      运行结果:

(2)Executors.newFixedThreadPool(int n):创建一个可重用固定个数的线程池,以共享的无界队列方式来运行这些线程。

 

      运行结果:

线程池大小为3,每个任务输出打印结果后sleep 1秒,所以每1秒打印3个结果。定长线程池的大小最好根据系统资源进行设置。

(3)Executors.newScheduledThreadPool(int n):创建一个定长线程池,支持定时及周期性任务执行。

 

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

 

      运行结果:


 四种线程池实现方式都是通过图片展现给各位老爷,就是希望大家可以自己敲下代码,加深印象,而不是做代码的搬运工。

内容如有疑问,请提出宝贵意见,互相交流探讨。

参考资料:https://www.cnblogs.com/dolphin0520/p/3932921.html

                  https://www.cnblogs.com/xiguadadage/p/10243332.html

                  https://blog.csdn.net/nihaomabmt/article/details/81667481

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值