java线程池详解

34 篇文章 0 订阅
4 篇文章 0 订阅

一、线程池状态

五个状态: RUNNING、SHUTDOWN、STOP、TIDYING、TERMINATED

线程池的管理使用的AtomicInteger实现原子管理,而使用位操作实现线程池状态的管理和线程池中线程个数的管理,巧妙的采用了高3位管理状态,低29位管理个数

// runState is stored in the high-order bits
private static final int RUNNING    = -1 << COUNT_BITS;
private static final int SHUTDOWN   =  0 << COUNT_BITS;
private static final int STOP       =  1 << COUNT_BITS;
private static final int TIDYING    =  2 << COUNT_BITS;
private static final int TERMINATED =  3 << COUNT_BITS;
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

//获取线程池的状态
private static int runStateOf(int c)     { return c & ~CAPACITY; }
//获取当前线程池中线程个数
private static int workerCountOf(int c)  { return c & CAPACITY; }
//重置线程池状态和现场个数
private static int ctlOf(int rs, int wc) { return rs | wc; }

RUNNING: 线程池初始化时的状态

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

SHUTDOWN:调用shutdown()函数

STOP:调用shutdownNow()函数

TIDYING: 尝试着去terminate

if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
     try {
         terminated();
     } finally {
         ctl.set(ctlOf(TERMINATED, 0));
         termination.signalAll();
     }
     return;
}

TERMINATED: 从上述代码可以看到,结束前我们还可以在terminated()做一些事情,ThreadPoolExecutor中这个方法是空实现

二、ThreadPoolExecutor的类体系

Executor接口定义了execute方法

ExecutorService接口定义shutdown和submit方法

AbstractExecutorService抽象方法定义了submit具体实现

ThreadPoolExecutor是来具体管理线程池的相关情况,其次,就是可以继承AbstractExecutorService自定义实现(目前自己还没到这水平。。。)

三、ThreadPoolExecutor构造函数

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;
    }

1、核心线程数

2、最大线程数

3、存活时间

4、时间单位

5、队列

6、线程工厂

7、拒绝策略

一般来说,都是自定义的,而Executors中定义的各式各样的线程池都是不同的具体参数

四、线程池的源码

public static void main(String[] args) {
    ExecutorService executorService = Executors.newCachedThreadPool();

    executorService.submit(
            () -> System.out.println("123")
    );

    executorService.shutdown();

}

执行的submit时,会进入AbstractExecutorService的submit中

    public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    }

接着执行execute,进入ThreadPoolExecutor

处理分为三步:

1、如果当前线程数小于corePoolSize,则新建Worker执行;

2、如果当前现场状态为RUNNING,则将任务加入队列并添加成功中

      2.1 、判断线程池当前状态是否为RUNNING,如果非,则需要移出队列,并按照拒绝策略拒绝该任务;

      2.2、如果当前状态为RUNNING,判断线程池中Worker数是否为0,如果为0,则新建Worker(不执行改任务?创建既启动);

      2.3、如果当前状态为RUNNING,且Worker数大于0,则怎么办?worker会不断得从队列中取出任务执行,因此只要入队成功即可

3、如果非RUNNING,或任务入队失败,则新建Worker,新建Worker失败则拒绝该任务。为何还要新建Worker呢?可以看看Executors.newCachedThreadPool()就是特殊情况

    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);
    }

以上三个问题的原因,估计都在addWorker中解决

首先看看Worker,它是一个内部类,定义在ThreadPoolExecutor中,且实现了Runnable,说明其可以作为线程执行

private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable
    {
        
        //worker运行的线程,
        final Thread thread;
        //执行的第一个任务
        Runnable firstTask;
        // 执行完的任务数
        volatile long completedTasks;

        //一定是第一个线程
        Worker(Runnable firstTask) {
            setState(-1); // inhibit interrupts until runWorker
            this.firstTask = firstTask;
            this.thread = getThreadFactory().newThread(this);
        }

        //执行
        public void run() {
            runWorker(this);
        }

        //实现并发控制
        ....
    }

从上述代码,我们可以知道,新建Worker的时候,会新建一个线程

回过头来,在看看addWorker()方法

  //firstTask 在增加创建核心线程或者入队失败时firstTask不空,这两种情况core的值不一样,具体可以看executor方法
  private boolean addWorker(Runnable firstTask, boolean core) {
        retry:    //整个for循环都在判断是否可以新加一个worker
        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 ||
                    //核心线程添加失败,会在executor中继续加入队列中
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                //线程数++
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                c = ctl.get();  // Re-read ctl
                if (runStateOf(c) != rs)
                    continue retry;
                // else CAS failed due to workerCount change; 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 {
                    // Recheck while holding lock.
                    // Back out on ThreadFactory failure or if
                    // shut down before lock acquired.
                    int rs = runStateOf(ctl.get());

                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        //加入worker池中
                        workers.add(w);
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                    //worker启动,在这里会执行worker的run()方法
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

当新建一个worker时,会同时启动它所属的线程

接着看其run方法时,实际上调用的runWorker方法

   final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
            //这里是一个while循环,如果是worker 的第一个任务,则执行task.run;
            //如果worker已经执行过了,则从队列中取出任务执行,达到了线程的重复使用
            while (task != null || (task = getTask()) != null) {
                w.lock();
                // If pool is stopping, ensure thread is interrupted;
                // if not, ensure thread is not interrupted.  This
                // requires a recheck in second case to deal with
                // shutdownNow race while clearing interrupt
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try {
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
                        task.run();
                    } catch (RuntimeException x) {
                        thrown = x; throw x;
                    } catch (Error x) {
                        thrown = x; throw x;
                    } catch (Throwable x) {
                        thrown = x; throw new Error(x);
                    } finally {
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
    }

我们都知道,构造函数中有个参数值,keepAliveTime,表示线程存活时间,那么什么时候进行worker回收呢?

答案在getTask()中

timedOut默认是false

下面的代码段的意思是

如果大于最大线程数,或者在keepAliveTime时间内没有从队列中拿到任务,则本worker就不伺候大爷们了

boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

if ((wc > maximumPoolSize || (timed && timedOut))
        && (wc > 1 || workQueue.isEmpty())) {
    if (compareAndDecrementWorkerCount(c))
        return null;
    continue;
}

try {
    Runnable r = timed ?
            workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
            workQueue.take();
    if (r != null)
        return r;
    timedOut = true;
} catch (InterruptedException retry) {
    timedOut = false;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值