美文网首页
JUC--线程池解析

JUC--线程池解析

作者: 噜啦噜啦嘞_d31b | 来源:发表于2021-06-13 15:51 被阅读0次
  1. ThreadPoolExecutor继承结构


    图片.png

    1.1 构造方法:七个参数的分别代表corePoolSize 核心线程数,maximumPoolSize,最大线程数,keepAliveTime 存活时间(也就是线程池中线程可以空闲的时间),unit存活时间的单位,workQueue阻塞队列,threadFactory线程工厂,handler拒绝策略.

  public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) 

1.2 线程池提交任务的方式有两种
public void execute(Runnable command),该方法是由Excutor顶层接口提供的
public Future<?> submit(Runnable task) ,该方法是由ExecutorService扩展接口提供。
由返回值类型可以看出一个可以异步的获取返回值结果。

  1. submit方法();该方法将task包装成一个RunnableFuture对象然后调用execute方法执行。
    public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    }
  1. execute()方法
    判断任务是否为空 如果是口则抛出空指针异常。
    然后获取当前线程池中线程的数量(线程池中的数量是通过成员变量原子整形变量ctl记录,分别用高3位记录线程池的状态和和低29位记录线程池中线程的个数)

线程池的状态
2.1. RUNNING,处于正常运行状态接受任务处理任务
2.2. SHUTDOWN,调用shutdown()方法后进入此状态,表示不在接受新任务,处理阻塞队列中的任务
2.3. STOP,调用shutdownNow()方法后进入此状态不接受新任务,不处理已添加的任,并且会中断正在处理的任务。
2.4. TIDYING, 当所有的任务已终止,ctl记录的”任务数量”为0,线程池会变为TIDYING状态,当线程池变为TIDYING状态时,会执行钩子函数terminated()。terminated()在ThreadPoolExecutor类中是空的,若用户想在线程池变为TIDYING时,进行相应的处理;可以通过重载terminated()函数来实现。
2.5. TERMINATED,线程池彻底终止,就变成TERMINATED状态。

进入具体的执行流程:
判断当前线程池中的线程数量是否小于核心线程数,如果小于则将创建工作线程Woker执行任务,否则继续进行判断当前线程池是否处于运行状态,如果运行则将当前任务加入阻塞队列(这里注意,如果阻塞队列是无界的则最大线程数也没有意义了因为会一直往队列里添加任务)进行等待,否则进行添加非核心线程addWorker(command, false)fasle表示是非核心线程,具体逻辑在addWorker方法实现

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()方法
core表示所添加的任务是否是核心线程
首先进入第一个for(;;)进入执行进行状态检查,然后进入第二个for(;;)使用CAS的方式将线程池中线程数量加1 , wc >= (core ? corePoolSize : maximumPoolSize))这句判断为区分核心线程数与非核心线程数的依据。
接下来进入第二个大逻辑块,先将当前线程包装为Worker对象(Woker为继承CAS类与实现runnable接口),获取到当前Worker的真正的处理线程,如果不为Null则获取全局锁进行添加工作线程,进入同步代码块判断线程池状态 wokers为当前线程池中所有工作线程池集合是一个HashSet,将工作线程添加到HashSet之后进行解锁,然后启动工作线程进入runWorker方法()

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

Worker类的runWorker方法(),首先进行解锁,这时候如果调用shutdown方法的话是允许被中断的,然后进入while循环判断当前任务是否为空如果为空则从任务队列中取元素,获取Woker上的锁,获取到之后进入任务的具体执行如果调用shutdown方法的话是不允许被中断的,判断线程池状态如果是stop则中断当前线程,否则执行任务的具体流程,执行完毕之后将task置空,将当前工作线程处理的任务数加一,解锁,继续调用gettask方法执行取任务执行任务的流程,退出while循环的条件为没有取到任务则退出completedAbruptly代表是抛出异常退出(true)还是正常退出(fasle)

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 (task != null || (task = getTask()) != null) {
                w.lock();
                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);
        }
    }

getTask()方法
timeOut代表是否获取超时
进入循环进行从任务队列中取任务,首先判断当前线程池的状态根据其他代码逻辑可知,如果处于shutdown状态并且任务队列为空的情况下则将当前工作线程数CAS减1然后return null将没有取代任务,如果处于stop状态则将当前线程池工作线程数减以不管任务队列是否还有任务。
如果线程池处于running状态,则获取当前线程池中线程的数量 然后用变量time标记为当前线程池线程是否设置超时时间或者当前线程数是否大于核心线程数。进行线程池中线程数量逻辑的判断,之后从任务队列里面取任务分为阻塞等待和定时将取到任务返回

 private Runnable getTask() {
        boolean timedOut = false; // Did the last poll() time out?
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }
            int wc = workerCountOf(c)
            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;
            }
        }
    }

processWorkerExit方法
为将去除工作线程后的处理工作,判断当前工作线程是否正常退出,如果因为异常退出则将线程数减1,然后获取全局锁,将该工作线程处理的任务数量加到总任务数量之中,从HashSet移除当前工作线程,解锁,尝试停止线程池。

private void processWorkerExit(Worker w, boolean completedAbruptly) {
        if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
            decrementWorkerCount();
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            completedTaskCount += w.completedTasks;
            workers.remove(w);
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
        int c = ctl.get();
        if (runStateLessThan(c, STOP)) {
            if (!completedAbruptly) {
                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
                if (min == 0 && ! workQueue.isEmpty())
                    min = 1;
                if (workerCountOf(c) >= min)
                    return; // replacement not needed
            }
            addWorker(null, false);
        }
    }

shutdown()方法在获取执行的时候会先要获取到Woker的锁然后再去工作线程
shutdownnow()则是直接进行中断不需要获取锁

java提供了Executors线程池的工具类


图片.png
  1. 固定线程数量线程池
    该线程池核心线程数与最大线程数数量相等,且工作线程的存活时间为0,阻塞队列使用的是无界阻塞队列基于链表,适用于可以预测线程数量的业务,或者服务器负载较重,对当前线程数量进行控制。
public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
  1. 单例线程池
    核心线程数与最大线程数都是1 ,其实最大线程数没有意义因为使用的是无界阻塞队列,所有任务都是按顺序执行的
    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
  1. 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲空间,如无可回重用时则创建新线程,队列采用的同步队列,只有当一个任务被取走的时候,才能加入下一个任务,类似于生产者消费者模式
    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
  1. 定时任务线程池使用延迟队列,可以实现任务的定时执行。
    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }

5.:创建一个拥有多个任务队列的线程池,可以减少连接数创建当前可用cpu数量的线程来并行执行,适用于大耗时的操作,可以并行来执行,底层使用forkjoin框架,实现任务窃取

    public static ExecutorService newWorkStealingPool(int parallelism) {
        return new ForkJoinPool
            (parallelism,
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
    }

相关文章

网友评论

      本文标题:JUC--线程池解析

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