线程并发—线程池

本文作者:黄海燕,叩丁狼高级讲师。原创文章,转载请注明出处。

1.1 为什么要使用线程池?

所谓线程池,其实和连接池的概念很像,就是在内存中实现创建好了多个线程,我们使用的时候直接从里面拿,不用的时候直接放回去,并且线程池我们是可以进行管理的,很好的控制多个线程,并且减少了创建和销毁的过程减小了内存中的消耗。

相比起普通的创建线程,线程池的好处:

  • 重用存在的线程,减少对象创建、消亡的开销,性能佳。
  • 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
  • 提供定时执行、定期执行、单线程、并发数控制等功能。

1.2 线程池常用类体系结构:

image.png

1.3 ThreadPoolExecutor类

Executor接口表示线程池,而ThreadPoolExecutor为Executor接口最常用的实现类。所以学线程池不能不先学习ThreadPoolExecutor。

ThreadPoolExecutor类中有四个公共的构造器,也就是我们可以通过访问构造器创建对象。

image.png

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {}
参数 参数描述
int corePoolSize: 表示允许线程池中允许同时运行的最大线程数。(线程池的核心池大小,在创建线程池之后,线程池默认没有任何线程。当有任务过来的时候才会去创建创建线程执行任务。换个说法,线程池创建之后,线程池中的线程数为0,当任务过来就会创建一个线程去执行,直到线程数达到corePoolSize 之后,就会被到达的任务放在队列中。)
int maximumPoolSize: 线程池允许的最大线程数,他表示最大能创建多少个线程。maximumPoolSize肯定是大于等于corePoolSize。
long keepAliveTime: 表示线程没有任务时最多保持多久然后停止。默认情况下,只有线程池中线程数大于corePoolSize时,keepAliveTime才会起作用。换句话说,当线程池中的线程数大于corePoolSize,并且一个线程空闲时间达到了keepAliveTime,那么就是shutdown。
TimeUnit unit: 约束keepAliveTime的时间单位,如:时、分、秒
BlockingQueue workQueue: 一个阻塞队列,用来存储等待执行的任务,当线程池中的线程数超过它的corePoolSize的时候,线程会进入阻塞队列进行阻塞等待。通过workQueue,线程池实现了阻塞功能。阻塞队列选择:ArrayBlockingQueue;LinkedBlockingQueue;SynchronousQueue;PriorityBlockingQueue;
ThreadFactory threadFactory: 线程工厂,创建线程的对象
RejectedExecutionHandler handler: 拒绝处理任务时的策略。

简单使用:

public class Demo {
    public static void main(String[] args) {
        ThreadPoolExecutor pool = new ThreadPoolExecutor(5,10,0,TimeUnit.MILLISECONDS,new ArrayBlockingQueue<>(10));
        for (int i = 0;i<50;i++){
            pool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            });
        }
        pool.shutdown();
    }
}

抛出异常:

报错原因是因为最大线程数只有10,任务数为50,任务数>最大线程数据时线程池会启用拒绝策略,我们没有传入拒绝策略,所以使用了默认策略AbortPolicy。

扫描二维码关注公众号,回复: 5222577 查看本文章

拒绝策略:

ThreadPoolExecutor内部类 内部类的描述
ThreadPoolExecutor.AbortPolicy 丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy 什么都不做,丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy 线程池为停止,丢弃队列最前面的任务,然后重新尝试执行任务
ThreadPoolExecutor.CallerRunsPolicy 线程池为停止,由调用本线程处理该任务,本线程调用任务的run方法。

1.4使用Executors创建创建线程池Executors线程池工具类,提供了一系列静态工厂方法用于创建各种线程池。列表如下:

方法名 方法描述
newFixedThreadPool(int nThreads) 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newWorkStealingPool(int parallelism) 创建持有足够线程的线程池来支持给定的并行级别,并通过使用多个队列,减少竞争,它需要穿一个并行级别的参数,如果不传,则被设定为默认的CPU数量。ForkJoinPool支持大任务分解成小任务的线程池
newSingleThreadExecutor() 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行****
newCachedThreadPool() 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。线程可以重复利用执行任务。默认为60s未使用就被终止和移除
newSingleThreadScheduledExecutor() 创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。
newScheduledThreadPool(int corePoolSize) 创建一个定长线程池,支持定时及周期性任务执行。

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/wolfcode_cn/article/details/87365396