zoukankan      html  css  js  c++  java
  • 线程池的优点及线程池的创建方式

    什么是线程池

    Java中的线程池是运用场景最多的并发框架,几乎所有需要异步或并发执行任务的程序都可以使用线程池。

    在开发过程中,合理地使用线程池能够带来3个好处。
    第一:降低资源消耗。通过重复利用机制已降低线程创建和销毁造成的消耗。
    第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
    第三:提高线程的可管理性。线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配、调优和监控。但是,要做到合理利用线程池,必须对其实现原理了如指掌。

    线程池作用

    线程池是为突然大量爆发的线程设计的,通过有限的几个固定线程为大量的操作服务,减少了创建和销毁线程所需的时间,从而提高效率。

    如果一个线程的时间非常长,就没必要用线程池了(不是不能作长时间操作,而是不宜。),况且我们还不能控制线程池中线程的开始、挂起、和中止。

    线程池的分类

    ThreadPoolExecutor

    Java是天生就支持并发的语言,支持并发意味着多线程,线程的频繁创建在高并发及大数据量是非常消耗资源的,因为java提供了线程池。在jdk1.5以前的版本中,线程池的使用是及其简陋的,但是在JDK1.5后,有了很大的改善。JDK1.5之后加入了java.util.concurrent包,java.util.concurrent包的加入给予开发人员开发并发程序以及解决并发问题很大的帮助。这篇文章主要介绍下并发包下的Executor接口,Executor接口虽然作为一个非常旧的接口(JDK1.5 2004年发布),但是很多程序员对于其中的一些原理还是不熟悉,因此写这篇文章来介绍下Executor接口,同时巩固下自己的知识。如果文章中有出现错误,欢迎大家指出。

    Executor框架的最顶层实现是ThreadPoolExecutor类,Executors工厂类中提供的newScheduledThreadPool、newFixedThreadPool、newCachedThreadPool方法其实也只是ThreadPoolExecutor的构造函数参数不同而已。通过传入不同的参数,就可以构造出适用于不同应用场景下的线程池,那么它的底层原理是怎样实现的呢,这篇就来介绍下ThreadPoolExecutor线程池的运行过程。

    1.corePoolSize

      线程池核心线程数,默认情况下,核心线程会在线程池中一直存活,即使它们处于闲置状态。如果ThreadPoolExecutor的allowCoreThreadTimeOut属性设置为true,那么闲置的核心线程在等待新任务到来时会有超时策略,这个时间间隔由keepAliveTime所指定的时长后,核心线程就会被终止。

    2.maximumPoolSize

    线程池所能容纳的最大线程数,当活动线程达到这个数值后,后续的新任务将被阻塞。

    3.keepAliveTime

    非核心线程闲置时的超时时长,超过这个时长,非核心线程就会被回收。当ThreadPoolExecutor的allowCoreThreadTimeOut属性设置为true时,keepAliveTime同样会作用于非核心线程。

    4.unit

    keepAliveTime 参数的时间单位。

    5.workQueue

    执行前用于保持任务的队列。此队列仅保持由 execute 方法提交的 Runnable 任务。

     

     

     

    线程池四种创建方式

    Java通过Executors(jdk1.5并发包)提供四种线程池,分别为:

    newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

    newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

    newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。

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

    newCachedThreadPool

    创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。示例代码如下:

    // 无限大小线程池 jvm自动回收

    ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();

    for (int i = 0; i < 10; i++) {

    final int temp = i;

    newCachedThreadPool.execute(new Runnable() {

     

    @Override

    public void run() {

    try {

    Thread.sleep(100);

    } catch (Exception e) {

    // TODO: handle exception

    }

    System.out.println(Thread.currentThread().getName() + ",i:" + temp);

     

    }

    });

    }

     

    总结: 线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。

    newFixedThreadPool

    创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。示例代码如下:

    ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(5);

    for (int i = 0; i < 10; i++) {

    final int temp = i;

    newFixedThreadPool.execute(new Runnable() {

     

    @Override

    public void run() {

    System.out.println(Thread.currentThread().getId() + ",i:" + temp);

     

    }

    });

    }

    总结:因为线程池大小为3,每个任务输出index后sleep 2秒,所以每两秒打印3个数字。

    定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors()

    newScheduledThreadPool

    创建一个定长线程池,支持定时及周期性任务执行。延迟执行示例代码如下:

    ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(5);

    for (int i = 0; i < 10; i++) {

    final int temp = i;

    newScheduledThreadPool.schedule(new Runnable() {

    public void run() {

    System.out.println("i:" + temp);

    }

    }, 3, TimeUnit.SECONDS);

    }

    表示延迟3秒执行。

    newSingleThreadExecutor

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

    ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();

    for (int i = 0; i < 10; i++) {

    final int index = i;

    newSingleThreadExecutor.execute(new Runnable() {

     

    @Override

    public void run() {

    System.out.println("index:" + index);

    try {

    Thread.sleep(200);

    } catch (Exception e) {

    // TODO: handle exception

    }

    }

    });

    }

    注意: 结果依次输出,相当于顺序执行各个任务。

    线程原理剖析

    提交一个任务到线程池中,线程池的处理流程如下:

    1、判断线程池里的核心线程是否都在执行任务,如果不是(核心线程空闲或者还有核心线程没有被创建)则创建一个新的工作线程来执行任务。如果核心线程都在执行任务,则进入下个流程。

    2、线程池判断工作队列是否已满,如果工作队列没有满,则将新提交的任务存储在这个工作队列里。如果工作队列满了,则进入下个流程。

    3、判断线程池里的线程是否都处于工作状态,如果没有,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和策略来处理这个任务。

  • 相关阅读:
    input只允许输入正整数
    CSS如何作小于1PX的边
    时间戳的处理
    图片转base64上传,视频同理。
    APIcloud微信支付和支付宝支付(方案2,主要在后台进行)
    H5滑条(input type=range)
    checkbox/radio 样式修改
    APIcloud制作APP 微信支付与支付宝支付
    JS获取鼠标左(右)滑事件
    DOM(Document object madle) 文档对象模型: 元素节点 文本节点 属性节点
  • 原文地址:https://www.cnblogs.com/ming-blogs/p/10555997.html
Copyright © 2011-2022 走看看