线程池的学习

Posted SSimeng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程池的学习相关的知识,希望对你有一定的参考价值。

1. 什么是线程池?

线程池:一种线程使用模式。 线程池就是首先创建一些线程,它们的集合称为线程池。
线程过多会带来调度开销,进而影响缓存局部性和整体性能,而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。使用线程池可以很好地提高性能,线程池在系统启动时即创建大量空闲的线程,程序将一个任务传给线程池,线程池就会启动一条线程来执行这个任务,执行结束以后,该线程并不会死亡,而是再次返回线程池中成为空闲状态,等待执行下一个任务。使用线程池避免了在处理短时间任务时创建与销毁线程的代价

2. 为什么要使用线程池?

线程池不仅能够保证内核的充分利用,还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量
好处:

  • 提高响应速度:当任务到达时,任务可以不需要等到线程创建就能立即执行
  • 降低资源销毁:通过重复利用已经创建的线程,降低线程创建和销毁造成的消耗
  • 防止服务器过载:形成内存溢出,或者CPU耗尽。
  • 提高线程的可管理性:线程是稀缺资源,如果无限制地创建,不仅会消耗资源,还会降低系统的稳定性,使用线程池可以进行统一的分配、调优和监控。

3. 常用的线程池有哪些?

  • (newCachedThreadPool)可缓存的线程池:该线程池中没有核心线程,非核心线程的数量为Integer.max_value。当有需要时创建线程来执行任务,没有需要时回收线程,适用于耗时少,任务量大的情况。
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
 	try {
           //sleep可明显看到使用的是线程池里面以前的线程,没有创建新的线程
             Thread.sleep(1000);
        } catch (InterruptedException e) {
              e.printStackTrace();
        }
        cachedThreadPool.execute(new Runnable() {
            public void run() {
               //打印正在执行的缓存线程信息
                System.out.println(Thread.currentThread().getName()+"正在被执行");
            }
        });
 }
  • (newScheduledThreadPool)周期性执行任务的线程池:按照某种特定的计划执行线程中的任务,有适用于执行周期性的任务。
 //创建一个定长线程池,支持定时及周期性任务执行——延迟执行
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
//延迟1秒执行
scheduledThreadPool.schedule(new Runnable() {
    public void run() {
          System.out.println("延迟1秒执行");
        }
}, 1, TimeUnit.SECONDS);
  • (newSingleThreadPool)单线程池只有一条线程来执行任务,适用于有顺序的任务的应用场景。
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
    for (int i = 0; i < 10; i++) {
          final int index = i;
          singleThreadExecutor.execute(new Runnable() {
              public void run() {
                   try {
                         //结果依次输出,相当于顺序执行各个任务
                         System.out.println(Thread.currentThread().getName()+"正在被执行,打印的值是:"+index);
                         Thread.sleep(1000);
                     } catch (InterruptedException e) {
                         e.printStackTrace();
                     }
                 }
          });
    }
  • (newFixedThreadPool)定长的线程池:有核心线程,核心线程数量即为最大的线程数量,没有非核心线程
 //创建一个可重用固定个数的线程池
 ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
 for (int i = 0; i < 10; i++) {
       fixedThreadPool.execute(new Runnable() {
           public void run() {
               try {
                    //打印正在执行的缓存线程信息
                       System.out.println(Thread.currentThread().getName()+"正在被执行");
                       Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
             }
        });
  }

4 线程池的配置参数。

5 线程池工作原理。

有新的任务时,首先判断核心线程是否处于空闲状态,如果是空闲状态,核线程就先执行任务,如果核心线程已满,则判断任务队列是否已满,如果没满就将任务保存在任务队列中,等待执行,如果满了,再判断有没有超出线程池最大可容纳的线程数,如果没有超出这个数量,就开创非核心线程执行任务,如果超出了,就调用handler实现拒绝策略。

6 线程池的handler拒绝策略

有四种:

  • 1.AbortPolicy:不执行新任务,直接抛出异常,提示线程池已满
  • 2.DisCardPolicy:不执行新任务,也不抛出异常
  • 3.DisCardOldSetPolicy:将消息队列中的第一个任务替换为当前新进来的任务执行
  • 4.CallerRunsPolicy:直接调用execute来执行当前任务

以上是关于线程池的学习的主要内容,如果未能解决你的问题,请参考以下文章

Java线程池详解

C++学习记录:一个小线程池的源码分析

C++学习记录:一个小线程池的源码分析

C++学习记录:一个小线程池的源码分析

Java-----关于线程池的使用

线程池的学习