java_线程池

作者: 飞翔的鲲 | 来源:发表于2018-02-22 21:39 被阅读65次

    Executors


    四种线程池

    1. newFixedThreadPool(int var0)
      固定线程数, 使用了LinkedBlockingQueue队列。
       public static ExecutorService newFixedThreadPool(int var0) {
            return new ThreadPoolExecutor(var0, var0, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue());
        }
    
    1. newCachedThreadPool()
     public static ExecutorService newCachedThreadPool() {
            return new ThreadPoolExecutor(0, 2147483647, 60L, TimeUnit.SECONDS, new SynchronousQueue());
        }
    
    1. newSingleThreadExecutor()
      单个线程任务,队列为LinkedBlockingQueue
        public static ExecutorService newSingleThreadExecutor() {
            return new Executors.FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()));
        }
    
    1. newScheduledThreadPool(int var0)
      定时任务,队列为DelayedWorkQueue
        public static ScheduledExecutorService newScheduledThreadPool(int var0) {
            return new ScheduledThreadPoolExecutor(var0);
        }
    
        public ScheduledThreadPoolExecutor(int corePoolSize) {
            super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
                  new DelayedWorkQueue());
        }
    
        public ThreadPoolExecutor(int corePoolSize,
                                  int maximumPoolSize,
                                  //线程空闲时的存活时间,即当线程没有任务执行时,继续存活的时间。默认情况下,该参数只在线程数大于corePoolSize时才有用
                                  long keepAliveTime,
                                  TimeUnit unit,
                                  BlockingQueue<Runnable> workQueue) {
            this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
                 Executors.defaultThreadFactory(), defaultHandler);
        }
    

    阻塞队列


    参考
    https://www.jianshu.com/p/4028efdbfc35

    阻塞队列是一种队列,一种可以在多线程环境下使用,并且支持阻塞等待的队列。也就是说,阻塞队列和一般的队列的区别就在于:
    1.多线程环境支持,多个线程可以安全的访问队列
    2.支持生产和消费等待,多个线程之间互相配合,当队列为空的时候,消费线程会阻塞等待队列不为空;当队列满了的时候,生产线 程就会阻塞直到队列不满。

    • LinkedBlockingDeque,双端阻塞队列
      使用了一个没有边界的链表来存储数据
    • ArrayBlockingQueue
      使用一个有边界的数组来作为存储介质
    • SynchronousQueue同步队列
      将任务直接交给线程处理而不保持它们
    • DelayQueue延时队列
      这是一个非常有趣的阻塞队列,你同样可以参考DelayedWorkQueue的实现

    非阻塞队列


    取的时候不会阻塞等待

    • ConcurrentLinkedQueue
      在底层,非阻塞队列使用的是CAS(compare and set)来实现线程执行的非阻塞。
      本身是一个基于链接节点的无界线程安全队列。原子性操作当然是线程安全的,非原子性那就不安全了
    • 入队方法:
    add():底层调用offer();
    
    offer():Queue接口继承下来的方法,实现队列的入队操作,不会阻碍线程的执行,插入成功返回true;
    
    • 出队方法:
    poll():移动头结点指针,返回头结点元素,并将头结点元素出队;队列为空,则返回null;
    
    peek():移动头结点指针,返回头结点元素,并不会将头结点元素出队;队列为空,则返回null;
    

    底层实现ThreadPoolExecutor


    Java线程池ThreadPoolExecutor使用和分析(一)
    http://www.cnblogs.com/trust-freedom/p/6594270.html
    Java线程池ThreadPoolExecutor使用和分析(二) - execute()原理
    https://www.cnblogs.com/trust-freedom/p/6681948.html

    • 执行流程
      当提交一个新任务到线程池时首先线程池判断基本线程池(corePoolSize)是否已满?没满,创建一个工作线程来执行任务。满了,则进入下个流程;其次线程池判断工作队列(workQueue)是否已满?没满,则将新提交的任务存储在工作队列里。满了,则进入下个流程;最后线程池判断整个线程池(maximumPoolSize)是否已满?没满,则创建一个新的工作线程来执行任务,满了,则交给饱和策略来处理这个任务;如果线程池中的线程数量大于 corePoolSize 时,如果某线程空闲时间超过keepAliveTime,线程将被终止,直至线程池中的线程数目不大于corePoolSize;如果允许为核心池中的线程设置存活时间,那么核心池中的线程空闲时间超过 keepAliveTime,线程也会被终止。
    image.png
    • 任务调度策略


      image.png
    image.png

    说明:

    在图1中,线程池中有N个任务。"任务1", "任务2", "任务3"这3个任务在执行,而"任务3"到"任务N"在阻塞队列中等待。正在执行的任务,在workers集合中,workers集合包含3个Worker,每一个Worker对应一个Thread线程,Thread线程每次处理一个任务。

    当workers集合中处理完某一个任务之后,会从阻塞队列中取出一个任务来继续执行,如图2所示。图2表示"任务1"处理完毕之后,线程池将"任务4"从阻塞队列中取出,放到workers中进行处理。

    • 完整构造方法
        public ThreadPoolExecutor(int corePoolSize, // 核心线程数
                                  int maximumPoolSize, // 最大线程数
                                  long keepAliveTime,
                                  TimeUnit unit,
                                  // 队列
                                  BlockingQueue<Runnable> workQueue,
                                  ThreadFactory threadFactory,
                                  // 拒绝执行处理器
                                  RejectedExecutionHandler handler) {
            if (corePoolSize < 0 ||
                maximumPoolSize <= 0 ||
                maximumPoolSize < corePoolSize ||
                keepAliveTime < 0)
                throw new IllegalArgumentException();
            if (workQueue == null || threadFactory == null || handler == null)
                throw new NullPointerException();
            this.corePoolSize = corePoolSize;
            this.maximumPoolSize = maximumPoolSize;
            this.workQueue = workQueue;
            this.keepAliveTime = unit.toNanos(keepAliveTime);
            this.threadFactory = threadFactory;
            this.handler = handler;
        }
    
    • 重要属性
    // 所有工作线程
    private final HashSet<Worker> workers = new HashSet<Worker>();
    // 存储runnable的队列
     private final BlockingQueue<Runnable> workQueue;
    
    • 重要方法
      1.execute提交任务


      image.png

    2.addWorker() -- 添加worker线程


    image.png

    3.runWorker() -- 执行任务
    会调用getTask()获取runnable


    image.png

    4.getTask() -- 获取任务
    从阻塞队列拿runnable


    image.png

    相关文章

      网友评论

        本文标题:java_线程池

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