线程池有感

134 阅读2分钟

先来看一下线程池的参数

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), handler);
    }

corePoolSize:表示线程池核心线程数
maximumPoolSize:线程池中最大允许的线程数 keepAliveTime+unit:额外线程(线程数大于corePoolSize,小于maximumPoolSize)最大空闲时间
workQueue:工作队列 存放未被执行的任务
handler:拒绝策略

先来看看这个ctl变量:高3位表示线程池的状态,低29位表示线程池中的线程数量,线程池初始状态为RUNNING,线程池中线程数为0

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
    }

来看核心方法execute(): 1.线程池中线程数量<corePoolSize,创建线程来处理任务 2.线程池中线程数量=corePoolSize,把任务放入等待队列中 3.当等待队列满了,线程池中线程数量<maximumPoolSize,会创建额外的线程来处理任务 4.当线程池中线程数量=maximumPoolSize,会根据拒绝策略来拒绝任务

下面我们来看看固定线程池是如何进行线程创建,线程加入线程池,执行任务的过程

ExecutorService executorService = Executors.newFixedThreadPool(3);

此时,第一个任务来了,先吃线程数量0<3,走addWorker(command, true)

private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;
            for (;;) {
                int wc = workerCountOf(c);
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                c = ctl.get();  // Re-read ctl
                if (runStateOf(c) != rs)
                    continue retry;
                    inner loop
            }
        }
        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                    int rs = runStateOf(ctl.get());
                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        workers.add(w);
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }
  //是通过CAS使线程数递增1
  if (compareAndIncrementWorkerCount(c))
                    break retry;
//给整个线程池上了独占锁
final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
    //然后加入线程池workers其实是个Hashset, Hashset线程不安全,所以需要加锁来保证线程安全           
    workers.add(w);
    //线程加入线程池后,需要释放锁
    finally {
        mainLock.unlock();
    }
    //需要来执行任务了,是走Worker.run(),再走任务task.run()
    t.start();
    final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        task.run();
    }
    //线程执行完当前任务后,会从阻塞队列里获取任务核心是getTask()方法
    走 LinkedBlokingQueue的workQueue.take();

固定线程池的工作队列用的是LinkedBlokingQueue有界阻塞队列,但是它的长度是Integet.MAX_VALUE...近似无界了。那么就有可能n多任务在阻塞队列里造成内存溢出