• 线程池原理(JDK1.8)


    线程池原理(JDK1.8)

    2018-08-06 16:30:37 食鱼酱 阅读数 318更多

    Java中的线程池

    ThreadPoolExecutor是线程池类。对于线程池,可以通俗的将它理解为”存放一定数量线程的一个线程集合。线程池允许若个线程同时允许,允许同时运行的线程数量就是线程池的容量;当添加的到线程池中的线程超过它的容量时,会有一部分线程阻塞等待。线程池会通过相应的调度策略和拒绝策略,对添加到线程池中的线程进行管理。

    组成(这部分转自线程池原理——skywang12345

    // 阻塞队列
    private final BlockingQueue<Runnable> workQueue;
    
    // 互斥锁
    private final ReentrantLock mainLock = new ReentrantLock();
    
    // 线程集合。一个Worker对应一个线程。
    private final HashSet<Worker> workers = new HashSet<Worker>();
    
    // “终止条件”,与“mainLock”绑定。
    private final Condition termination = mainLock.newCondition();
    
    // 线程池中线程数量曾经达到过的最大值。
    private int largestPoolSize;
    
    // 已完成任务数量
    private long completedTaskCount;
    
    // ThreadFactory对象,用于创建线程。
    private volatile ThreadFactory threadFactory;
    
    // 拒绝策略的处理句柄。
    private volatile RejectedExecutionHandler handler;
    
    // 保持线程存活时间。
    private volatile long keepAliveTime;
    
    private volatile boolean allowCoreThreadTimeOut;
    
    // 核心池大小
    private volatile int corePoolSize;
    
    // 最大池大小
    private volatile int maximumPoolSize;

    1.workers

    workers是HashSet类型,即它是一个Worker集合。而一个Worker对应一个线程,也就是说线程池通过workers包含了”一个线程集合”。当Worker对应的线程池启动时,它会执行线程池中的任务;当执行完一个任务后,它会从线程池的阻塞队列中取出一个阻塞的任务来继续运行。 
    wokers的作用是,线程池通过它实现了”允许多个线程同时运行”。

    2.workQueue

    workQueue是BlockingQueue类型,即它是一个阻塞队列。当线程池中的线程数超过它的容量的时候,线程会进入阻塞队列进行阻塞等待。 
    通过workQueue,线程池实现了阻塞功能。

    3. mainLock

    mainLock是互斥锁,通过mainLock实现了对线程池的互斥访问。

    4. corePoolSize和maximumPoolSize

    corePoolSize是”核心池大小”,maximumPoolSize是”最大池大小”。它们的作用是调整”线程池中实际运行的线程的数量”。 
    例如,当新任务提交给线程池时(通过execute方法)。 
    – 如果此时,线程池中运行的线程数量< corePoolSize,则创建新线程来处理请求。 
    – 如果此时,线程池中运行的线程数量> corePoolSize,但是却< maximumPoolSize;则仅当阻塞队列满时才创建新线程。 
    如果设置的 corePoolSize 和 maximumPoolSize 相同,则创建了固定大小的线程池。如果将 maximumPoolSize 设置为基本的无界值(如 Integer.MAX_VALUE),则允许池适应任意数量的并发任务。在大多数情况下,核心池大小和最大池大小的值是在创建线程池设置的;但是,也可以使用 setCorePoolSize(int) 和 setMaximumPoolSize(int) 进行动态更改。

    5. poolSize

    poolSize是当前线程池的实际大小,即线程池中任务的数量。

    6. allowCoreThreadTimeOut和keepAliveTime

    allowCoreThreadTimeOut表示是否允许”线程在空闲状态时,仍然能够存活”;而keepAliveTime是当线程池处于空闲状态的时候,超过keepAliveTime时间之后,空闲的线程会被终止。

    7. threadFactory

    threadFactory是ThreadFactory对象。它是一个线程工厂类,”线程池通过ThreadFactory创建线程”。

    8. handler

    handler是RejectedExecutionHandler类型。它是”线程池拒绝策略”的句柄,也就是说”当某任务添加到线程池中,而线程池拒绝该任务时,线程池会通过handler进行相应的处理”。


     

    原理(源码是JDK1.8)

     public void execute(Runnable command) {
         if (command == null)
             throw new NullPointerException();
    
         int c = ctl.get();
         /*
             1、判断当前的工作线程是否小于线程池里的核心线程,如果满足,则创建一个新的工作线程来执行任务。
             如果不满足,则进入下个流程。
    
             注意:此时addWorker的第二个参数为true;
         */ 
         if (workerCountOf(c) < corePoolSize) {
             if (addWorker(command, true))
                 return;
             c = ctl.get();
         }
         /*
            2、线程池判断工作队列是否已满,如果工作队列没有满,则将新提交的任务存储在这个工作队列里。
            如果工作队列满了,则进入下个流程。
        */
         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);
         }
         //3、尝试创建线程    注意:此时addWorker的第二个参数为false,下面会解释
         else if (!addWorker(command, false))
             reject(command);
     }
    
    //该方法用于创建线程,注意该方法的第二个参数core
    private boolean addWorker(Runnable firstTask, boolean core) {
            retry:
            for (;;) {
                int c = ctl.get();
                int rs = runStateOf(c);
    
                // Check if queue empty only if necessary.
                if (rs >= SHUTDOWN &&
                    ! (rs == SHUTDOWN &&
                       firstTask == null &&
                       ! workQueue.isEmpty()))
                    return false;
    
                for (;;) {
                    int wc = workerCountOf(c);
                    /*
                        当core为false时,下面判断线程池corePoolSize和maximumPoolSize 的差值,如果此时,
                        线程池中运行的线程数量> corePoolSize,但是却< maximumPoolSize,则会继续创建一个
                        新的工作线程。
                    */
                    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;
                    // 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();
                            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;
        }
    •  

    总结

    1、判断当前的工作线程是否小于线程池里的核心线程,如果满足,则创建一个新的工作线程来执行任务。不满足则进入下个流程。

    2、线程池判断工作队列是否已满,如果工作队列没有满,则将新提交的任务存储在这个工作队列里。如果工作队列满了,则进入下个流程。

    3、判断线程池corePoolSize和maximumPoolSize 的差值,如果此时,线程池中运行的线程数量> corePoolSize,但是却< maximumPoolSize,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和策略来处理这个任务。

  • 相关阅读:
    pycharm 社区版运行flask app相关配置
    飞冰框架学习记录
    从上一次到现在总结2
    从上一次到今天的总结1
    mybatis 遇到空串无法判断
    Shell 脚本入门
    数据库批量插入数据
    Navicat for mysql 实现数据库自动备份
    自定义校验注解
    C++ 提高编程
  • 原文地址:https://www.cnblogs.com/grj001/p/12223595.html
Copyright © 2020-2023  润新知