线程池的深度学习

 一:线程池


 1.1 什么是线程池?

就是一种多线程的处理方式,处理过程可以将我们的任务添加到队列中,然后再创建线程后自动启动这些任务
这里的线程就是昨天晚间学习的线程,这里的任务就是继承Thread 实现 Runnable实例对象!!

1.2 使用线程池的优势:

1.2.1 线程和任务是分离的,提高线程的重用性。
1.2.2 控制线程的并发数量,降低服务器的压力 统一管理所有的线程 
1.2.3 提升系统的响应速度  3   5  2 


1.3 线程池的应用场景


    秒杀
    12306购票

1.4 java中内置的线程池 ThreadPoolExecutor
     java.util.concurrent  Class ThreadPoolExecutor

public ThreadPoolExecutor(int corePoolSize,  //核心线程数量
                          int maximumPoolSize,//最大的线程数量 
                          long keepAliveTime, //最大的空闲时间 
                          TimeUnit unit,      //时间单位
                          BlockingQueue<Runnable> workQueue, // 任务队列 
                          ThreadFactory threadFactory,  //线程工厂
                          RejectedExecutionHandler handler)//饱和处理机制 


1.5 线程池工作流程 

1.6自定义线程池 

 corePoolSize 核心线程数量 

 1个任务 0.1秒  
 100个任务
 1秒内完成 
 我们需要10个线程 

 workQueue 任务队列
 核心线程数/每个任务的执行时间*2   
   10个  单个任务的执行时间是 0.1秒 设计为200 

maximumPoolSize  //最大的线程数量 
如果系统每秒钟产生1000个
最大线程数=(最大任务数-任务队列的长度)*单个任务的执行时间  

最大线程数=(1000-200)* 0.1=80个


keepAliveTime 最大的空闲时间  没有固定的数据 根据实际的运行环境 

1.7自定义线程类实现步骤 

 1.编写任务类
 2.线程类
 3.线程池类
 4.写测试类

1.8 Java中内置的线程池  ExecutorService
  通过学习接口中的方法,可以快速掌握java内置线程池的基本使用!!
  java.util.concurrent Interface ExecutorService [ExecutorService]

   void shutdown() 启动一次顺序关闭 
   List<Runnable> shutdownNow() 停止所有正在执行的任务, 暂停处理正在等待的任务,并返回等待执行任务列表!
   <T> Future<T> submit(Callable<T> task)  执行带返回值的任务,返回一个Future对象给我们!
   Future<?> submit(Runnable task)   执行Runnable的任务,返回一个Future对象给我们!
   <T> Future<T> submit(Runnable task,T result)  执行Runnable的任务,返回一个Future对象给我们!


   如何创建 ExecutorService呢???
    public static ExecutorService newCachedThreadPool() 创建一个默认的线程池对象,里面的线程可以重用!

    public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory)
        线程池中所有的线程都使用 ThreadFactory来创建 ,这样的线程不需要手动启动,自动执行!

   public static ExecutorService newFixedThreadPool(int nThreads)
     调用该方法课程创建线程池对象,同时指定线程池中的线程个数【通过参数nThreads进行指定】

   public static ExecutorService newFixedThreadPool(int nThreads,ThreadFactory threadFactory)
     创建一个可重用的固定线程数的线程池,所有的线程都由ThreadFactory来创建!

    public static ExecutorService newSingleThreadExecutor() 
      创建一个使用单个worker 线程的 Executor ,以无界队列的方式去执行线程

    public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory)
    创建一个使用单个worker 线程的 Executor ,且线程池中的所有的线程都使用ThreadFactory来创建!!

1.9 java内置的线程池 

ScheduledExecutorService  具备延迟运行的能力!
public interface ScheduledExecutorService extends ExecutorService {

 public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
  创建一个线程池,可以调度命令在一个给定的延迟后运行,或周期性地执行。

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize,ThreadFactory threadFactory)
    创建一个线程池,可以调度命令在一个给定的延迟后运行,或周期性地执行。 

public static ScheduledExecutorService newSingleThreadScheduledExecutor()
    创建一个单线程的执行程序,它允许延迟执行!!!

    public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory)
    

 二: 关于线程池的一些常见面试题?

1. ThreadPoolExecutor 有哪些常用的方法?

        ThreadPoolExecutor有如下常用方法:

submit()/execute():执行线程池
shutdown()/shutdownNow():终止线程池
isShutdown():判断线程是否终止
getActiveCount():正在运行的线程数
getCorePoolSize():获取核心线程数
getMaximumPoolSize():获取最大线程数
getQueue():获取线程池中的任务队列
allowCoreThreadTimeOut(boolean):设置空闲时是否回收核心线程
        这些方法可以用来终止线程池、线程池监控。

2. 说说submit(和 execute两个方法有什么区别?

        submit() 和 execute() 都是用来执行线程池的,只不过使用 execute() 执行线程池不能有返回方法,而使用 submit() 可以使用 Future 接收线程池执行的返回值。

3. 说说线程池创建需要的那几个核心参数的含义

        ThreadPoolExecutor 最多包含以下七个参数:

corePoolSize:线程池中的核心线程数
maximumPoolSize:线程池中最大线程数
keepAliveTime:闲置超时时间
unit:keepAliveTime 超时时间的单位(时/分/秒等)
workQueue:线程池中的任务队列
threadFactory:为线程池提供创建新线程的线程工厂
rejectedExecutionHandler:线程池任务队列超过最大值之后的拒绝策略


4. shutdownNow() 和 shutdown() 两个方法有什么区别?

        shutdownNow() 和 shutdown() 都是用来终止线程池的,它们的区别是,使用 shutdown() 程序不会报错,也不会立即终止线程,它会等待线程池中的缓存任务执行完之后再退出,执行了 shutdown() 之后就不能给线程池添加新任务了;shutdownNow() 会试图立马停止任务,如果线程池中还有缓存任务正在执行,则会抛出 java.lang.InterruptedException: sleep interrupted 异常。

5. 了解过线程池的工作原理吗?

        当线程池中有任务需要执行时,线程池会判断如果线程数量没有超过核心数量就会新建线程池进行任务执行,如果线程池中的线程数量已经超过核心线程数,这时候任务就会被放入任务队列中排队等待执行;如果任务队列超过最大队列数,并且线程池没有达到最大线程数,就会新建线程来执行任务;如果超过了最大线程数,就会执行拒绝执行策略。


6. 线程池中核心线程数量大小怎么设置?

        CPU密集型任务:比如像加解密,压缩、计算等一系列需要大量耗费 CPU 资源的任务,大部分场景下都是纯 CPU 计算。尽量使用较小的线程池,一般为CPU核心数+1。 因为CPU密集型任务使得CPU使用率很高,若开过多的线程数,会造成CPU过度切换。

IO密集型任务: 比如像 MySQL 数据库、文件的读写、网络通信等任务,这类任务不会特别消耗 CPU 资源,但是 IO 操作比较耗时,会占用比较多时间。 可以使用稍大的线程池,一般为2*CPU核心数。 IO密集型任务CPU使用率并不高,因此可以让CPU在等待IO的时候有其他线程去处理别的任务,充分利用CPU时间。

另外:线程的平均工作时间所占比例越高,就需要越少的线程;线程的平均等待时间所占比例越高,就需要越多的线程;

以上只是理论值,实际项目中建议在本地或者测试环境进行多次调优,找到相对理想的值大小。

7. 线程池为什么需要使用(阻塞)队列?

        主要有三点:

因为线程若是无限制的创建,可能会导致内存占用过多而产生OOM,并且会造成cpu过度切换。
创建线程池的消耗较高。
8. 线程池为什么要使用阻塞队列而不使用非阻塞队列?

        阻塞队列可以保证任务队列中没有任务时阻塞获取任务的线程,使得线程进入wait状态,释放cpu资源。 当队列中有任务时才唤醒对应线程从队列中取出消息进行执行。 使得在线程不至于一直占用cpu资源。

(线程执行完任务后通过循环再次从任务队列中取出任务进行执行,代码片段如下 while (task != null || (task = getTask()) != null) {})。

9. 不用阻塞队列也是可以的,不过实现起来比较麻烦而已,有好用的为啥不用呢?

10. 了解线程池状态吗?

        通过获取线程池状态,可以判断线程池是否是运行状态、可否添加新的任务以及优雅地关闭线程池等。

RUNNING: 线程池的初始化状态,可以添加待执行的任务。
SHUTDOWN:线程池处于待关闭状态,不接收新任务仅处理已经接收的任务。
STOP:线程池立即关闭,不接收新的任务,放弃缓存队列中的任务并且中断正在处理的任务。
TIDYING:线程池自主整理状态,调用 terminated() 方法进行线程池整理。
TERMINATED:线程池终止状态。
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值