美文网首页Java 核心技术
并发编程-线程池

并发编程-线程池

作者: 迦叶_金色的人生_荣耀而又辉煌 | 来源:发表于2020-12-02 07:21 被阅读0次

    上一篇 <<<CyclicBarrier屏障
    下一篇 >>>并发队列


    线程池的作用

    第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
    第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
    第三:提高线程的可管理性。线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,
    还会降低系统的稳定性,使用线程池可以进行统一分配、调优和监控。但是,要做到合理利用
    第四:提供更多更强大的功能:线程池具备可拓展性,允许开发人员向其中增加更多的功能。比如延时定时线程池ScheduledThreadPoolExecutor,就允许任务延期执行或定期执行。

    线程池的创建方式

    1.newCachedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
    2.newFixedThreadPool :创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
    3.newScheduledThreadPool :创建一个定长线程池,支持定时及周期性任务执行。
    4.newSingleThreadExecutor :创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

    为什么需要开发者自己基于ThreadPoolExecutor构造函数封装

    答案:
    a.因为底层都是基于无界队列实现, 缓存线程队列可以无限的存放容量大小,有可能会内存溢出。
    b.线程池中最大线程数是无效的。

    OOM问题

    线程池原理剖析

    1、判断线程池里的核心线程是否都在执行任务,如果不是(核心线程空闲或者还有核心线程没有被创建)则创建一个新的工作线程来执行任务。如果核心线程都在执行任务,则进入下个流程。
    2、线程池判断工作队列是否已满,如果工作队列没有满,则将新提交的任务存储在这个工作队列里。如果工作队列满了,则进入下个流程。
    3、判断线程池里的线程是否都处于工作状态,如果没有,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和策略来处理这个任务。

    核心参数

    corePoolSize: 核心池的大小。 当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中
    maximumPoolSize: 线程池最大线程数,它表示在线程池中最多能创建多少个线程;
    keepAliveTime: 表示线程没有任务执行时最多保持多久时间会终止。
    unit: 参数keepAliveTime的时间单位,有7种取值,在TimeUnit类中有7种静态属性:
    workQueue 缓存线程队列。
    threadFactory 线程池内部创建线程所用的工厂
    handler 任务无法执行时的处理器,也就是拒绝策略回调方法

    为什么要用阻塞队列
    使用阻塞队列,可以复用,降低创建线程的消耗

    核心线程数和最大线程数的区别
    核心线程数是最大运行线程数
    最大线程数是最大创建线程数
    核心不能大于最大

    线程池的状态

    a.RUNNING:线程池能够接受新任务,以及对新添加的任务进行处理。
    b.SHUTDOWN:线程池不可以接受新任务,但是可以对已添加的任务进行处理。
    c.STOP:线程池不接收新任务,不处理已添加的任务,并且会中断正在处理的任务。
    d.TIDYING:当所有的任务已终止,ctl记录的"任务数量"为0,线程池会变为TIDYING状态。当线程池变为TIDYING状态时,会执行构造函数terminated()。terminated()在ThreadPoolExecutor类中是空的,若用户想在线程池变为TIDYING时,进行相应的处理;可以通过重载terminated()函数来实现。
    e.TERMINATED:线程池彻底终止的状态。

    线程池的拒绝场景及策略

    拒绝场景:
    a.当线程数已经达到maxPoolSize,切队列已满,会拒绝新任务
    b.当线程池被调用shutdown()后,会等待线程池里的任务执行完毕,再shutdown。如果在调用shutdown()和线程池真正shutdown之间提交任务,会拒绝新任务。
    拒绝策略:
    a.AbortPolicy【默认】 丢弃任务,抛运行时异常
    b.CallerRunsPolicy 执行任务
    c.DiscardPolicy 忽视,什么都不会发生
    d.DiscardOldestPolicy 从队列中踢出最先进入队列(最后一个执行)的任务
    e.实现RejectedExecutionHandler接口,可自定义处理器

    线程拒绝后如何处理保证不丢失?
    使用try方式捕获记录到日志中,后期定时或者人工补偿。

    线程池如何配置

    IO密集型:大量IO操作,容易造成IO阻塞,可配置多线程,每个阻塞互不影响。
    可配置多个线程 2*CPU盒数—任务管理器就可以看见
    CPU密集型:线程没等待,不会产生阻塞时,线程数等于CPU盒数

    execute和submit方法的区别

    a、submit可以支持多种,execute只支持runnable
    b、submit有Future返回值,execute返回void

    Executors和Executor区别

    Executor是接口类,ThreadPoolExecutor就是他的子类
    public interface Executor {
    void execute(Runnable command);
    }
    工具类,提供很多静态的方法
    public class Executors {
    public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
    0L, TimeUnit.MILLISECONDS,
    new LinkedBlockingQueue<Runnable>());
    }
    ……
    }

    手写线程池的思路


    相关文章链接:
    多线程基础
    线程安全与解决方案
    锁的深入化
    锁的优化
    Java内存模型(JMM)
    Volatile解决JMM的可见性问题
    Volatile的伪共享和重排序
    CAS无锁模式及ABA问题
    Synchronized锁
    Lock锁
    AQS同步器
    Condition
    CountDownLatch同步计数器
    Semaphore信号量
    CyclicBarrier屏障
    并发队列
    Callable与Future模式
    Fork/Join框架
    Threadlocal
    Disruptor框架
    如何优化多线程总结

    相关文章

      网友评论

        本文标题:并发编程-线程池

        本文链接:https://www.haomeiwen.com/subject/kfndwktx.html