【java基础】线程池-代码篇

原理:http://www.importnew.com/19011.html#comment-578619
    1、线程池状态
        一个Volatile几个static final
        volatile int runState;//当前池的状态,保证线程间可见性,下面是其可能的值
            static final int RUNNING    = 0;//创建后初始时处于此状态
            static final int SHUTDOWN   = 1;//调用shutdown,处此态:不接受新任务,等所有任务执行完毕
            static final int STOP       = 2;//shutdownNow,处此态,不接受新任务,尝试止正执行任务
            static final int TERMINATED = 3;//池处shutdown/stop态,线程销毁、任务缓存队列清空、执行结束,池置此态
    2、任务的执行
        ThreadPoolExecutor类中部分成员变量
            workQueue:任务缓存队列,存放等待执行的任务
            ReentrantLock mainLock池的主要状态,状态改变使用此锁
            HashSet<Worker> workers存放工作集
            keepAliveTime:线程存活时间
            allowCoreThreadTimeOut:是否容许为核心线程设置存活时间
            corePoolSize:核心池大小,大于此、提交的任务会被放进任务缓存队列
            maximunPoolSize:池max容忍的线程数
                新任务数量增长速度大于处理任务的速度、此来补救
            poolSize:当前线程数
            RejectedExecutionHandler handler:任务拒绝策略
            ThreadFactory threadFactory:线程工厂,用来创建线程
            largestPoolSize:用来记录线程池中曾经出现过的最大线程数
            completedTaskCount:用来记录已经执行完毕的任务个数
        execute()
            public void execute(Runnable command) {
                if (command == null)
                    throw new NullPointerException();//任务为null空指针
                if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {
                //当前线程数不小于核心池大小
                    if (runState == RUNNING && workQueue.offer(command)) {
                    //当前池处RUNNING态 && 任务放入任务缓存队列
                        if (runState != RUNNING || poolSize == 0)
                        //为了防止在将此任务添加进任务缓存队列时其他线程突然调用shutdown或shutdownNow关闭了池
                            //保证 添加到任务缓存队列中的任务得到处理
                            ensureQueuedTaskHandled(command);
                    }
                    else if (!addIfUnderMaximumPoolSize(command))
                    //执行addIfUnderMaximumPoolSize失败,任务拒绝处理
                        reject(command); // is shutdown or saturated
                }
            }
        addIfUnderCorePoolSize
        //当低于核心池大小时执行
            private boolean addIfUnderCorePoolSize(Runnable firstTask) {
                Thread t = null;
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();//获取锁
                try {
                //线程池中线程数是否小于核心池大小(防止其他线程提交新任务)
                //判断是否为running(万一其他线程调用shutdown或shutdownNow)
                    if (poolSize < corePoolSize && runState == RUNNING)
                        t = addThread(firstTask); //创建线程去执行firstTask任务
                    } finally {
                    mainLock.unlock();
                }
                if (t == null)
                    return false;//为空创建失败
                t.start();
                return true;
            }
        addThread
            private Thread addThread(Runnable firstTask) {
                Worker w = new Worker(firstTask);//用提交的任务创建worker
                Thread t = threadFactory.newThread(w);  //创建一个线程,执行任务
                if (t != null) {
                    w.thread = t;            //将创建的线程的引用赋值为w的成员变量
                    workers.add(w);//添加到工作集中
                    int nt = ++poolSize;     //当前线程数加1
                    if (nt > largestPoolSize)
                        largestPoolSize = nt;
                }
                return t;
            }
        worker类实现略
        总结:
            1、池中数<corePoolSize,来任务执行
            2、池中数>=corePoolSize,来任务,添加缓存队列,成功 任务等待空闲线程将其取出执行
                添加失败(任务缓存队列满)尝试创建新线程去执行
            3、池中数>=maximumPoolSize,采取任务拒绝策略
            4、池中数>corePoolSize
                某线程空闲时间超过keepAliveTime,线程终止,直到池中数<=cPS
                如果容许为核心池设置存活时间,池中线程空闲时间超过keepAliveTime,终止
    3、线程池中线程的初始化
        创建池后,提交任务后创建线程
            需创建后立即创建线程:
                1、prestartCoreThread初始化一个核心线程
                2、prestartAllCoreThreads初始化所有核心线程
                public boolean prestartCoreThread() {
                    return addIfUnderCorePoolSize(null); //注意传进去的参数是null
                }
                public int prestartAllCoreThreads() {
                    int n = 0;
                    while (addIfUnderCorePoolSize(null))//注意传进去的参数是null
                        ++n;
                    return n;
                }
    4、任务缓存队列及排队策略
        1)ArrayBlockingQueue:基于数组的先进先出队列,此队列创建时必须指定大小;
        2)LinkedBlockingQueue:基于链表的先进先出队列,如果创建时没有指定此队列大小,则默认为Integer.MAX_VALUE;
        3)synchronousQueue:这个队列比较特殊,它不会保存提交的任务,而是将直接新建一个线程来执行新来的任务
    5、任务拒绝策略
        任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize
        ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
        ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
        ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
        ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
    6、线程池的关闭

    7、池容量的动态调整
        setCorePoolSize:设置核心池大小
        setMaximumPoolSize:设置线程池最大能创建的线程数目大小
创建线程池:推荐方法
    Executors.newCachedThreadPool();        //创建一个缓冲池,缓冲池容量大小为Integer.MAX_VALUE
    Executors.newSingleThreadExecutor();   //创建容量为1的缓冲池
    Executors.newFixedThreadPool(int);    //创建固定容量大小的缓冲池
    ……
http://www.importnew.com/19011.html#comment-578619

后语:

    对博客的一些提炼,代码部分还有一些没有转过来,感谢大神的分享


猜你喜欢

转载自blog.csdn.net/ma15732625261/article/details/80840744