ThreadPoll线程池

ThreadPoll线程池

为什么要用线程池

线程池做的工作主要是控制运行的数量,处理过程中将任务放到队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量,超出数量的线程排队等候,等到其他线程执行完毕,再从队列中取出任务来执行。

主要特点:线程复用,控制最大并发数,管理线程

优势:

  1. 降低资源消耗,重复利用已经创建好的线程
  2. 提高响应速度,当任务到达时,任务不需要创建线程就可以立刻执行
  3. 提高线程可管理性:线程池可以进行统一的分配,调优,和监控

连接池同理

线程池如何使用

public class PoolDemo {
    public static void main(String[] args) {
        //建立线程池,有各种实现类,不同的实现类有不同的特性
        ExecutorService threadPool = Executors.newFixedThreadPool(3);//银行有n个窗口,1池n线程,线程数不会变
        ExecutorService threadPool2 = Executors.newSingleThreadExecutor();//银行有1个窗口,1池1线程,线程数不会变
        ExecutorService threadPool3 = Executors.newCachedThreadPool();//银行有可扩展窗口
        try {
            for (int i = 0; i < 3000; i++) {
                threadPool3.execute(() -> {
                            System.out.println(Thread.currentThread().getName() + "\t号业务员办理业务");
                        }); }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool3.shutdown();//关闭线程池
        }
    }
}

线程池的底层原理

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>(),
                                  threadFactory);
}
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {

创建线程池都是返回ThreadPoolExecutor对象,并且设置一些参数:

  1. corePoolSize:线程池里面常驻的线程数,银行里面日常开放的柜台,惰性加载
  2. maximumPoolSize:最大线程数,当银行来人多的话,柜台就开的多
  3. keepAliveTime:空闲线程存活时间,没有任务时,不需要坐班的人,需要留着的时间,时间到就下班。值班的还在。
  4. TimeUnit unit:时间单位
  5. workQueue:任务队列,提交还没有执行的任务
  6. threadFactory:线程工厂
  7. handler:拒绝策略,银行人太多了,把顾客拒绝到门外

工作原理:

  1. 当线程池初始化完成时,实际上一个线程都没有。
  2. 当开始执行时,先判断有没有核心线程,没有的话就直接创建,有的话就分配任务
  3. 当核心线程全部被分配时,任务先放入任务队列中等待,直到任务队列存满,则在不超过最大线程的前提下,扩充线程,但是这个时候创建的新的线程会处理新来的任务,而不是队列中等候的任务。
  4. 当出现线程空闲时,达到时间后,销毁多出来的线程
  5. 当高峰时,线程全部占满,队列占满,则开始拒绝任务

拒绝策略

当线程最大数量达到了,队列也满了,就需要拒绝策略了

jdk内置策略:

  1. AbortPoilcy:默认策略,直接异常
  2. callerRunPoilcy:哪里来的回到哪里去,返回到调用者
  3. DiscardOldestPoily:抛弃队列里面最久的任务,给新任务让出位置
  4. DiscardPoily:默默丢弃无法处理的任务,不处理,不异常。

一般不使用Excutor去创建,而是通过ThreadPoolExecutor来创建,避免资源耗尽的风险

阿里巴巴开发手册

最好手写线程池,将参数自己设置

public class PoolDemo {
    public static void main(String[] args) {
        //建立线程池,有各种实现类,不同的实现类有不同的特性
//        ExecutorService threadPool = Executors.newFixedThreadPool(3);//银行有n个窗口,1池n线程,线程数不会变
//        ExecutorService threadPool2 = Executors.newSingleThreadExecutor();//银行有1个窗口,1池1线程,线程数不会变
//        ExecutorService threadPool3 = Executors.newCachedThreadPool();//银行有可扩展窗口

        ExecutorService threadPool3 = new ThreadPoolExecutor(2,5,3L,TimeUnit.SECONDS,
                new ArrayBlockingQueue<Runnable>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy());

        try {
            for (int i = 0; i < 30; i++) {
                threadPool3.execute(() -> {
                            System.out.println(Thread.currentThread().getName() + "\t号业务员办理业务");
                        }); }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool3.shutdown();//关闭线程池
        }
    }
}
上一篇:Pytest之断言


下一篇:JavaSE:线程池